首页 > 解决方案 > 有条件地选择要在 FOR LOOP 中迭代的集合

问题描述

我想知道我是否可以在循环中执行 if-elsif 或 case-when。在 for 循环之间没有,但作为 for 循环的一个状态,可以在 select 或另一个之间进行选择。像这样的东西:

我已经尝试过 if-elsif 和 case-when ……但它们都没有奏效,我一直潜伏在网上寻找一些东西,但没有。

CREATE OR REPLACE FUNCTION myfunct(op integer, -vars-)
RETURNS table(-vars-)
LANGUAGE plpgsql
AS $function$
DECLARE 
  selectop record;
  -vars-
BEGIN
  FOR selectop in (IF (op=1) THEN
                             SELECT * FROM mytab WHERE somevar=true;
                   ELSIF (op=2) THEN
                             SELECT * from mytab WHERE somevar=false;
                   END IF;)
      -things-
  RETURN NEXT;
  LOOP
    ---THINGS---
 END;
$function$

标签: postgresqlfor-loopif-statementcaseplpgsql

解决方案


我想知道为什么你不只是设置一个变量并在查询中使用它。这似乎容易得多。但从学术的角度来看,这是一个有趣的问题。

问题是IFCASE作为控制结构不返回某些东西或评估某些东西。所以我们不能以这种方式使用它们。

如果我们考虑返回一些东西,那么我们可能会想到函数。所以你可以在那里放置一个函数调用,它根据参数返回不同的集合。但似乎您想要的功能应该完全实现,所以这只会将问题转移到另一个层面并最终无限。

所以让我们考虑评估一些东西。表达式出现在我们的脑海中,确实有CASE一个表达式,我们可以用它来切换。唯一的事情是,至少据我所知,它不能处理集合。

但它可以处理数组。所以这个想法是使用一个CASE表达式,它计算为(两个)不同的数组。

我们将使用这样一个事实,即每个表还在 Postgres 中定义了一个类型,即其行的类型。所以我们将遍历该类型的数组。

Postgres 中的下一个巧妙的事情是,我们可以使用它array_agg()来将完整的表或它的子集聚合到一个数组中。这就是我们将如何创建我们迭代的数组。

要遍历数组,我们将使用FOREACH循环。(是的,这不是FOR游标上的循环,但在语义上我猜这已经足够接近了。)

这样的函数可能如下所示。elbat是我们的表和nmuloc4我们想要比较值的列,具体取决于函数参数的值switch。该函数返回一个SETOF elbat,即来自 的一组记录elbat

CREATE FUNCTION noitcnuf
                (switch integer)
RETURNS SETOF elbat
AS
$$
DECLARE
  elbat_array elbat[];
  elbat_element elbat;
BEGIN
  FOREACH elbat_element IN ARRAY(CASE
                                   WHEN switch = 1 THEN
                                     (SELECT array_agg(elbat)
                                             FROM elbat
                                             WHERE nmuloc4 = true)
                                   WHEN switch = 2 THEN
                                     (SELECT array_agg(elbat)
                                             FROM elbat
                                             WHERE nmuloc4 = false)
                                   ELSE
                                     ARRAY[]::elbat[]
                                 END) LOOP
    RETURN NEXT elbat_element;
  END LOOP;

  RETURN;
END;
$$
LANGUAGE plpgsql;

db<>小提琴

ELSE分支中,CASE我们只有一个正确类型的空数组。CASE否则,如果我们将参数传递给在出口中没有分支的函数,我们会收到错误消息。像这样,我们只是在这种情况下得到空集。

请注意,这也适用于视图甚至可能是集合返回函数而不是表(我没有明确测试后者)。

但我也想警告一下,我怀疑这种方法的性能可能比仅仅根据变量构建查询并在游标上执行经典循环或最多将其减少为基于集合的方法而没有循环全部。


推荐阅读