В примерах предыдущей и данной лекций присутствовало много запросов с соединениями двух или более таблиц. Условия соединения задавались предикатами сравнения столбцов таблиц, специфицированных в разделе FROM, и входили в состав логических выражений раздела WHERE (или, реже, раздела HAVING). Поскольку на практике требуются разные виды соединений, в стандарте SQL/92 появилась альтернативная возможность спецификации соединений – соединенная таблица (joined table). Соответствующая конструкция может использоваться в разделе FROM выражения запросов и фактически позволяет строить выражения соединений таблиц. Синтаксические правила построения таких выражений выглядят следующим образом:
joined_table ::= cross_join
| qualified_join
| natural_join
| union_join
cross_join ::= table_reference CROSS JOIN table_primary
qualified_join ::= table_reference [ join_type ] JOIN
table_primary join_specification
natural_join ::= table_reference NATURAL [ join_type ]
JOIN table_primary
union_join ::= table_reference UNION JOIN table_primary
join_type ::= INNER | { LEFT | RIGHT | FULL } [ OUTER ]
join_specification ::= ON conditional_expression
| USING (column_comma_list)
Напомним, что синтаксические правила для table_reference и table_primary были показаны в подразделе 17.3.2. Ссылки на таблицы раздела FROM лекции 17.
Как показывает сводка синтаксических правил, в SQL поддерживается много вариантов соединений. Чтобы объяснить особенности разных видов соединений на неформальном уровне, требуется очень большой объем текста с большим числом повторений. Поэтому сначала мы приведем достаточно формальное описание порядка определения заголовка и тела результирующей таблицы для всех разновидностей соединений. Фактически это описание напрямую позаимствовано из стандарта SQL:1999 с некоторыми незначительными упрощениями. Затем мы представим ряд иллюстрирующих примеров.
Пусть требуется выполнить некоторую операцию соединения над таблицами table1 и table2. Тогда:
CP результат выполнения запроса144)
SELECT * FROM table1, table2
JOIN (или NATURAL JOIN) без явного указания типа соединения (join_type), то по умолчанию имеется в виду INNER JOIN (или NATURAL INNER JOIN).join_specification) указано ключевое слово ON, то все ссылки на столбцы, встречающиеся в условном выражении (conditional_expression), должны указывать на столбцы таблиц table1 и table2 или на столбцы таблиц внешнего запроса. Если в этом условном выражении присутствует вызов агрегатной функции, то соединенная таблица может фигурировать только в подзапросах, используемых в разделах HAVING или SELECT внешнего запроса, и ссылка на столбец в вызове функции должна указывать на столбец таблицы внешнего запроса.CROSS JOIN) и всех других видов соединения, включающих раздел ON, заголовок результата операции совпадает с заголовком таблицы CP.NATURAL или USING, то заголовок результата операции определяется следующим образом:
NATURAL, то будем называть соответствующими столбцами соединения (corresponding join column) все столбцы таблиц table1 и table2, которые имеют в заголовках этих таблиц одинаковые имена. Если в спецификации вида соединения присутствует ключевое слово USING, то будем называть соответствующими столбцами соединения (corresponding join column) все столбцы таблиц table1 и table2, имена которых входят в список имен столбцов раздела USING (эти столбцы должны быть одноименными в заголовках обеих таблиц). В обоих случаях типы данных каждой пары соответствующих столбцов должны быть совместимыми; select_list of corresponding join columns – SLCC) список элементов вида COALESCE (table1.c, table2.c) AS c*, где с145) является именем соответствующего столбца соединения. Элементы располагаются в том порядке, в котором они появляются в заголовке таблицы table1. Обозначим через SLT1 (SLT2) список имен столбцов таблицы table1 (table2), которые не являются соответствующими столбцами соединения. Имена располагаются в том же порядке, в котором они появляются в заголовке соответствующей таблицы;SELECT SLCC, SLT1, SLT2 FROM table1, table2;
T следующие наборы строк:
UNION JOIN, то T – пусто;CROSS JOIN, то T включает все строки, входящие в CP;ON, то T включает все строки CP, для которых результатом вычисления условного выражения является true;NATURAL или USING, и список SLCC не является пустым, то T включает все строки CP, для которых значения соответствующих столбцов соединения совпадают146);NATURAL или USING, и список SLCC является пустым, то T включает все строки CP.P1 (P2) набор (множество или мультимножество) всех строк таблицы table1 (table2), каждая из которых участвует в образовании некой строки T.U1 (U2) набор (множество или мультимножество) всех строк таблицы table1 (table2), ни одна из которых не участвует в образовании какой-либо строки T.X1 набор (множество или мультимножество) всех строк, образуемых из строк набора U1 путем добавления справа подстроки из неопределенных значений, содержащей столько неопределенных значений, сколько столбцов содержит таблица table2. Обозначим через X2 набор (множество или мультимножество) всех строк, образуемых из строк набора U2 путем добавления слева подстроки из неопределенных значений, содержащей столько неопределенных значений, сколько столбцов содержит таблица table1.CROSS JOIN и INNER JOIN пусть S обозначает тот же набор строк, что и T.LEFT OUTER JOIN пусть S обозначает набор строк, являющийся результатом выражения запросов
SELECT * FROM T UNION ALL SELECT * FROM X1;
RIGHT OUTER JOIN пусть S обозначает набор строк, являющийся результатом выражения запросов
SELECT * FROM T UNION ALL SELECT * FROM X2;
FULL OUTER JOIN пусть S обозначает набор строк, являющийся результатом выражения запросов
SELECT * FROM T UNION ALL SELECT * FROM X1 UNION ALL SELECT * FROM X2;
UNION JOIN пусть S обозначает набор строк, являющийся результатом выражения запросов
SELECT * FROM X1 UNION ALL SELECT * FROM X2;
NATURAL или USING, то результат операции совпадает с результатом выражения запросов
SELECT SLCC, SLT1, SLT2 FROM S;
S. 144 Интересно, что для этого запроса возможна альтернативная формулировка с использованием операции CROSS JOIN: SELECT * FROM table1 CROSS JOIN table2. Может возникнуть естественный вопрос: зачем вводить специальную конструкцию для декартова произведения? По мнению автора, эта конструкция была введена, главным образом, для повышения уровня общности языка SQL. Кроме того, использование явного ключевого слова CROSS JOIN является подтверждением того, что пользователь действительно может получить декартово произведение, а не упустил по ошибке раздел WHERE.
145 Для удобства читателей напомним, что по определению выражение COALESCE (V1, V2) эквивалентно следующему выражению с переключателем: CASE WHEN V1 IS NOT NULL THEN V1 ELSE V2 END.
146 Совпадают в строгом смысле, т.е. значение столбца table1.c совпадает со значением столбца table2.c тогда и только тогда, когда значением операции сравнения table1.c = table2.c является true.