Каково ожидаемое поведение для нескольких функций, возвращающих множество в предложении select?
Я пытаюсь получить "перекрестное соединение" с результатом двух возвращающих множество функций, но в некоторых случаях я не получаю "перекрестное соединение", см. Пример
Поведение 1. Когда длина набора совпадает, он соответствует элементу из каждого набора
postgres=# SELECT generate_series(1,3), generate_series(5,7) упорядочить на 1,2; generate_series | generate_series -----------------+----------------- 1 | 5 2 | 6 3 | 7 (3 ряда)
Поведение 2: Когда длины набора отличаются, это "перекрестное соединение" наборов
postgres=# SELECT generate_series(1,2), generate_series(5,7) упорядочить на 1,2; generate_series | generate_series -----------------+----------------- 1 | 5 1 | 6 1 | 7 2 | 5 2 | 6 2 | 7 (6 рядов)
Я думаю, что я чего-то здесь не понимаю, может кто-нибудь объяснить такое поведение?
РЕДАКТИРОВАТЬ: еще один пример, более странный, чем предыдущий
postgres=# SELECT generate_series(1,2) x, generate_series(1,4) y упорядочить по x,y; х | Y ---+--- 1 | 1 1 | 3 2 | 2 2 | 4 (4 ряда)
(ПРИМЕЧАНИЕ: я приму ответ, который отвечает на вопрос названия со ссылкой на документацию.)
3 ответа
Postgres 10 или новее
добавляет нулевые значения для меньшего набора (ей). Демо-версия:
SELECT generate_series( 1, 2) AS row2
, generate_series(11, 13) AS row3
, generate_series(21, 24) AS row4;
row2 | row3 | row4 ----- + ------ + ----- 1 | 11 | 21 2 | 12 | 22ноль | 13 | 23ноль | ноль | 24
dbfiddle здесь
Если в списке выбора запроса имеется более одной функции, возвращающей множество, то поведение аналогично тому, как вы получаете, помещая функции в один
LATERAL ROWS FROM( ... )
FROM
пункт Для каждой строки из базового запроса есть выходная строка, использующая первый результат из каждой функции, затем выходная строка, использующая второй результат, и так далее. Если некоторые из функций, возвращающих наборы, выдают меньше выходных данных, чем другие, вместо отсутствующих данных подставляются нулевые значения, поэтому общее число строк, выданных для одной базовой строки, такое же, как и для функции, возвращающей набор, которая выдает наибольшее количество выходных данных, Таким образом, функции, возвращающие множество, запускаются "в режиме ожидания" до тех пор, пока все они не будут исчерпаны, а затем выполнение продолжается со следующей строки.
Это заканчивает традиционно странное поведение.
Postgres 9,6 или старше
Число строк результата (несколько удивительно!) Является наименьшим общим кратным из всех наборов в одном и том же SELECT
список. (Только как CROSS JOIN
если все размеры набора не имеют общего делителя!) Демонстрация:
SELECT generate_series( 1, 2) AS row2
, generate_series(11, 13) AS row3
, generate_series(21, 24) AS row4;
row2 | row3 | row4 ----- + ------ + ----- 1 | 11 | 21 2 | 12 | 22 1 | 13 | 23 2 | 11 | 24 1 | 12 | 21 2 | 13 | 22 1 | 11 | 23 2 | 12 | 24 1 | 13 | 21 2 | 11 | 22 1 | 12 | 23 2 | 13 | 24
dbfiddle здесь
Документально описан в руководстве по Postgres 9.6 глава " Функции SQL, возвращающая наборы", вместе с рекомендацией избегать этого:
Примечание. Основная проблема заключается в использовании функций, возвращающих наборы, в списке выбора, а не в
FROM
предложение состоит в том, что помещение более одной функции, возвращающей множество в один и тот же список выбора, ведет себя не очень разумно. (Что вы на самом деле получаете, если делаете это, так это количество выходных строк, равное наименьшему общему числу, кратному количеству строк, произведенных каждой функцией, возвращающей набор.)LATERAL
синтаксис дает менее неожиданные результаты при вызове нескольких функций, возвращающих множество, и обычно должен использоваться вместо этого.
Жирный акцент мой.
Одиночная функция возврата набора в порядке (но в FROM
список), но несколько в том же SELECT
список не рекомендуется сейчас. Это была полезная функция, прежде чем мы имели LATERAL
присоединяется. Теперь это просто исторический балласт.
Связанные с:
Единственное замечание о проблеме в документации. Я не уверен, объясняет ли это описанное поведение или нет. Возможно, более важным является то, что использование таких функций не рекомендуется:
В настоящее время функции, возвращающие наборы, также можно вызывать в списке выбора запроса. Для каждой строки, которую запрос генерирует сам по себе, вызывается функция, возвращающая набор, и для каждого элемента набора результатов функции генерируется выходная строка. Однако обратите внимание, что эта возможность устарела и может быть удалена в будущих выпусках.
Я не могу найти документацию для этого. Тем не менее, я могу описать поведение, которое я наблюдаю.
Каждая порождающая функция множества возвращает конечное число строк. Кажется, Postgres запускает функции, генерирующие множество, пока все они не окажутся в последней строке - или, скорее, остановятся, когда все вернутся к своим первым строкам. Технически это будет наименьшее общее кратное (LCM) длин серий.
Я не уверен, почему это так. И, как я говорю в комментарии, я думаю, что лучше вообще поместить функции в from
пункт.