Диалект T-SQL давно известен мощным синтаксисом CROSS APPLY
и OUTER APPLY
синтаксисом JOIN. В стандарте SQL: 1999 были введены почти эквивалентные «боковые производные таблицы», которые в конечном итоге поддерживаются PostgreSQL 9.3 или Oracle 12c , которые приняли как стандартный LATERAL
синтаксис SQL, так CROSS APPLY
и специфичные для поставщика T-SQL и OUTER APPLY
синтаксисы.
Но о чем мы вообще говорим?
Функции SQL обладают уникальной чертой, которой обладают немногие другие языки. Они не понятны тем, кто их не знает, поскольку каждая языковая функция вводит новый синтаксис с новыми ключевыми словами. В этом случае: APPLY
и LATERAL
. Но это действительно не так сложно понять. Все, что вы делаете с a CROSS APPLY
, это CROSS JOIN
между двумя таблицами, где правая часть выражения объединения может ссылаться на столбцы с левой стороны выражения соединения. Рассмотрим следующий пример Мартина Смита о переполнении стека :
Повторное использование псевдонимов столбцов
SELECT number, doubled_number, doubled_number_plus_one FROM master..spt_values CROSS APPLY ( SELECT 2 * CAST(number AS BIGINT) ) CA1(doubled_number) CROSS APPLY ( SELECT doubled_number + 1 ) CA2(doubled_number_plus_one)
Смотрите SQLFiddle из приведенного выше примера
В этом примере мы выбираем числа из системной таблицы и применяем скалярный подвыбор, умножая каждое число на два. Затем ко всему продукту таблицы мы перекрестно применяем еще один скалярный подвыбор, добавляя его к последнему числу.
Этот конкретный пример также может быть реализован с использованием подзапросов в SELECT
предложении. Но, как вы можете видеть в приведенном выше примере, doubled_number_plus_one
можно рассчитать из ранее рассчитанного столбца за один раз. Это не было бы так просто с подзапросами.
Применение табличных функций к каждой записи
SELECT * FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle)
Этот пример может быть еще более полезен, когда вы хотите присоединить табличную функцию к каждой записи другой таблицы.
ЛАТЕРАЛЬНЫЕ производные таблицы PostgreSQL
В PostgreSQL это можно сделать каким-то волшебным образом, поместив табличные функции в SELECT
предложении:
SELECT x, GENERATE_SERIES(0, x) FROM (VALUES(0), (1), (2)) t(x)
Смотрите SQLFiddle из приведенного выше примера
Вышеуказанные урожаи
| X | GENERATE_SERIES | |---|-----------------| | 0 | 0 | | 1 | 0 | | 1 | 1 | | 2 | 0 | | 2 | 1 | | 2 | 2 |
В качестве альтернативы, начиная с PostgreSQL 9.3, вы можете использовать явную боковую производную таблицу как
SELECT x, y FROM (VALUES(0), (1), (2)) t(x), LATERAL GENERATE_SERIES(0, t.x) u(y)
Смотрите SQLFiddle из приведенного выше примера
Уступая снова
| X | Y | |---|---| | 0 | 0 | | 1 | 0 | | 1 | 1 | | 2 | 0 | | 2 | 1 | | 2 | 2 |
CROSS APPLY и OUTTER APPLY в jOOQ 3.3
Вышеуказанные пункты также будут поддерживаться в следующих выпусках jOOQ 3.3, где вы можете написать запросы, подобные этому:
DSL.using(configuration) .select() .from(AUTHOR) .crossApply( select(count().as("c")) .from(BOOK) .where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))) .fetch();
Или боковые присоединения:
DSL.using(configuration) .select() .from( values(row(0), row(1), row(2)) .as("t", "x"), lateral(generateSeries(0, fieldByName("t", "x")) .as("u", "y"))) .fetch();
Неважно, используете ли вы jOOQ или собственный SQL, таблицы с боковыми производными или CROSS APPLY
обязательно должны быть частью вашей замечательной цепочки инструментов SQL!