有条件地选择要在FOR LOOP中进行迭代的集合

时间:2019-01-04 23:22:10

标签: postgresql for-loop if-statement case plpgsql

我想知道在循环内是否可以执行if-elsif或case-。在for循环之间不存在,但作为foor循环的一种方式在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$

1 个答案:

答案 0 :(得分:0)

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

问题在于,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<>fiddle

ELSE的{​​{1}}分支中,我们只有一个正确类型的空数组。否则,如果将参数传递给该函数,而CASE中的任何分支都不存在,则会收到错误消息。这样,在这种情况下,我们只得到空集。

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

但是我也想警告一下,我怀疑这种方法的性能可能不仅仅取决于根据变量建立查询并在游标上进行经典循环,或者最多只能将其简化为基于集合的方法,根本没有循环。