Почему существует различие в поведении между использованием функции возврата набора (SRF) в списке SELECT и использованием SRF в предложении FROM?
Например, для простого SRF, возвращающего 2 строки:
CREATE OR REPLACE FUNCTION gen_series(out integer, out int)
RETURNS SETOF record AS $$
SELECT 1,1
UNION
SELECT 2,2;
$$ LANGUAGE SQL;
SELECT gen_series();
возвращает две строки одного столбца, каждая из которых содержит запись:
=> gen_series
------------
(1,1)
(2,2)
(2 rows)
Принимая во внимание, что SELECT * FROM gen_series();
возвращает две строки с расширенной записью:
=> column1 | column2
---------+---------
1 | 1
2 | 2
(2 rows)
Для сравнения: если SRF возвращает один столбец, то вызов SRF в предложении SELECT или FROM не имеет значения. например:
=> SELECT generate_series(1,2);
generate_series
-----------------
1
2
(2 rows)
=> SELECT * FROM generate_series(1,2);
generate_series
-----------------
1
2
(2 rows)
Мои вопросы:
Я не совсем понимаю, почему во втором случае поведение SRF отличается от первого случая только потому, что возвращаемая таблица имеет один столбец. Это действительно последовательное поведение с точки зрения типов, кортежей и множеств?
Какая разница между двумя случаями, которая приводит к разному поведению?
SRF можно использовать в качестве таблиц, как показано выше, но можно ли использовать таблицы для замены SRF? например
SELECT my_table;
По-видимому, этого нельзя сделать, но почему это SELECT my_SRF();
возможно, а
SELECT my_table;
не разрешено (с точки зрения отношений и математики)?
SELECT my_table;
недопустимый синтаксисОтветы:
Postgres относится к простому случаю по-другому. Несколько столбцов обрабатываются как составной тип (строка таблицы), который разделяется только на один
SELECT * FROM ...
, в то время как один столбец скалярного типа обрабатывается только как это, без добавления оболочки составного типа. Так чтоSELECT my_SRF()
выдает так же, как иSELECT * FROM my_SRF()
для простого случая. Руководство по табличным функциям :Я согласен, что это сбивает с толку, и вы не первый, кто запутался. (Однако рассмотрим альтернативный вариант: добавление обертки составного типа вокруг одного столбца может быть еще более запутанным.)
Но не так запутанно, как то, что происходит, когда вы комбинируете несколько функций SRF в
SELECT
списке. Это изменится с Postgres 10 навсегда, хотя:Безопасный, менее запутанный способ для любого случая - переместить функции SRF в
FROM
предложение. ИспользуйтеLATERAL
объединение, если вам нужно сослаться на столбцы из другой таблицы. Руководство предлагает:источник