Условно выбрал набор для итерации в цикле FOR LOOP - PullRequest
0 голосов
/ 05 января 2019

Я хотел бы знать, могу ли я делать if-elsif или case-внутри цикла. Не между циклом for, а как утверждение цикла foor, чтобы выбрать между выбором или другим. как то так:

Я пробовал и с 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 голосов
/ 05 января 2019

Интересно, почему вы не просто задали переменную и используете ее в запросе? Это кажется намного проще. Но с академической точки зрения это интересный вопрос.

Проблема в том, что IF или CASE в качестве управляющей структуры не возвращают что-либо или что-то оценивают. Поэтому мы не можем использовать их таким образом.

Если мы думаем о возвращении чего-то, то мы можем думать о функциях. Таким образом, вы можете разместить там вызов функции, который возвращает другой набор в зависимости от аргумента. Но похоже, что функция, которую вы хотите иметь, должна реализовывать именно это, так что это просто переместит проблему на другой уровень и в конечном итоге до бесконечности.

Итак, давайте подумаем об оценке чего-либо. Выражения приходят нам на ум, и действительно есть 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;

дб <> скрипка

В ELSE ветви CASE у нас просто есть пустой массив правильного типа. В противном случае мы получим ошибку, если передадим аргумент функции, для которой нет выхода из CASE. Таким образом, мы просто получаем пустой набор в таком случае.

Обратите внимание, что это также будет работать для представления или, возможно, даже для функции, возвращающей множество вместо таблицы (я явно не проверял последнюю).

Но я также хотел бы предупредить, что я подозреваю, что этот подход, вероятно, будет менее производительным, чем простое построение запроса в зависимости от переменных и выполнение классического цикла над курсором или в лучшем случае сведение его к подходу на основе множеств с петель нет вообще.

...