Интересно, почему вы не просто задали переменную и используете ее в запросе? Это кажется намного проще. Но с академической точки зрения это интересный вопрос.
Проблема в том, что 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
. Таким образом, мы просто получаем пустой набор в таком случае.
Обратите внимание, что это также будет работать для представления или, возможно, даже для функции, возвращающей множество вместо таблицы (я явно не проверял последнюю).
Но я также хотел бы предупредить, что я подозреваю, что этот подход, вероятно, будет менее производительным, чем простое построение запроса в зависимости от переменных и выполнение классического цикла над курсором или в лучшем случае сведение его к подходу на основе множеств с петель нет вообще.