Выбрать главу

Подзапросы

Подзапросом является оператор SELECT, включенный в другой запрос. Внедренный запрос, встроенный запрос, вложенный запрос являются синонимами для подзапроса. Подзапросы используются с различными условиями для чтения данных из других таблиц в основной (внешний для подзапроса) запрос. Правила составления подзапросов изменяются в соответствии с целью подзапроса. Прочитанные данные всегда являются данными только для чтения.

Запросы UNION

Запросы объединения дают возможность выбрать строки соответствующих форматов из различных наборов данных в объединенный набор данных, который приложения могут использовать так, как если бы он был одной таблицей только для чтения. Подмножества, найденные в таблицах, не обязательно должны быть связаны друг с другом - просто они должны соответствовать друг другу структурно.

Соединения

Соединение используется в операторах SELECT для генерации ненормализованных наборов, содержащих столбцы из нескольких таблиц, которые хранят связанные данные. Множества столбцов, выбранных из каждой таблицы, называются потоками. Процесс соединения объединяет выбранные столбцы в единый выходной набор данных. Простейшим случаем является соединение двух таблиц, которые связаны соответствием элементов ключа, встречающихся в обеих таблицах.

Для создания связи ключевые столбцы выбираются на основании того, что они реализуют недвусмысленное отношение - т. е. ключ в левой таблице соединения будет отыскивать только те строки из правой таблицы, которые соответствуют отношению, и он будет отыскивать все такие строки. Обычно связь осуществляется между уникальным ключом левой таблицы (первичный или любой другой уникальный ключ) и формальным или подразумеваемым внешним ключом правой таблицы.

Тем не менее условия соединения не ограничены столбцами первичного и внешнего ключей; сервер допускает в выходном наборе данных дубликаты строк. Дублированные строки могут стать причиной нежелательного результата. По этому вопросу обратитесь к замечаниям в разд. "Темы оптимизации".

Внутреннее соединение

Следующий оператор соединяет две таблицы, которые связаны через внешний ключ FK правой таблицы (Table2) и первичный ключ PK таблицы Table1:

SELECT

Таblе1.PK,

Table1.COL1,

Table2.PKX,

Table2.COLX

FROM Table1 INNER JOIN Table2

ON Table1.PK = Table2.FK

WHERE... условия-поиска

Это спецификация внутреннего соединения. Вскоре мы рассмотрим внешнее соединение. На рис. 22.1 показаны два потока, как они существуют в таблицах, и генерируемый набор данных.

Рис. 22.1. Внутреннее соединение

Как показывает диаграмма, внутреннее соединение объединяет два потока таким образом, что несоответствующие строки в любом из потоков отбрасываются. Другое название внутреннего соединения - исключающее соединение, поскольку его правила означают, что несоответствующие пары обоих потоков исключаются из выходного набора данных.

Стандарты SQL описывают два варианта синтаксиса внутреннего соединения. Предыдущий пример использует более современный синтаксис SQL-92, отличающийся от более старого, более ограниченного SQL-89, указывая явное соединение, потому что в примере используется явное предложение JOIN для задания условий соединения.

Синтаксис неявного INNER JOIN в SQL-89

В стандарте SQL-89 таблицы, участвующие в соединении, задаются списком с разделяющими запятыми в предложении FROM запроса SELECT. Условия для связи таблиц задаются среди условий поиска предложения WHERE. Не существует специального синтаксиса для указания, какие условия используются для поиска, а какие - для соединения. Предполагается, что условия соединения самоочевидны. Обратившись назад, к введению в предложение JOIN, можно назвать старый синтаксис неявным соединением.

Синтаксис неявного соединения может осуществлять только внутреннее соединение - реализация SQL, которая не поддерживает предложение JOIN, не может выполнять внешнее соединение.

Вот предыдущий пример, который переписан как неявное соединение:

SELECT

Table1.PK,

Table1.COL1,

Table2.PKX,

Table2.COLX

FROM Table1, Table2

WHERE Table1.PK = Table2.FK

AND <условия-поиска>

Неявное соединение поддерживается в Firebird для совместимости с кодом существующих приложений. Оно не рекомендуется для новых приложений, потому что оно несовместимо с синтаксисом других видов соединений и делает поддержку и само- документируемость довольно неуклюжей. Некоторые программы доступа к данным, включая драйверы, могут не обрабатывать правильно синтаксис SQL-89 по причине проблем при синтаксическом анализе в различении условий соединения и условий поиска. Можно предположить, что в будущем стандарте этот синтаксис будет отсутствовать.

Синтаксис явного INNER JOIN в SQL-92

Явное внутреннее соединение является предпочтительным для Firebird и других реляционных СУБД, которые его поддерживают. Если оптимизатор способен вычислить план запроса, то неважно, что синтаксис SQL-92 будет лучше или хуже более раннего синтаксиса, потому что интерпретатор DSQL будет транслировать любой оператор в идентичную двоичную форму для анализа ее оптимизатором.

Явное соединение делает код оператора более читаемым и согласованным с другими стилями соединения, поддерживаемыми SQL-92 и последующими стандартами. Иногда его синтаксис называют синтаксисом условного соединения, потому что структура предложения JOIN. .. ON дает возможность отличать условия соединения от условий поиска. Не удивительно, такое использование термина "условное" может все запутать!

Ключевое слово INNER совсем необязательно и обычно опускается. Присутствие только слова JOIN имеет точно тот же смысл, что и INNER JOIN. (Если слову JOIN предшествуют LEFT, RIGHT или FULL, то это не является внутренним соединением.)

Три или более потока

Если существует более двух потоков (таблиц), просто добавляйте предложения JOIN. .. ON для каждого отношения. Следующий пример добавляет третий поток в предыдущий пример, соединяя его со вторым потоком через другой внешний ключ отношения:

SELECT

Table1.PK,

Table1.COL1,

Table2.PK,

Table2.COLX,

Table3.COLY

FROM Table1 JOIN Table2

ON Table1.PK = Table2.FK

JOIN Table3 ON TABLE2.PKX = Table3.FK

WHERE Table3.STATUS = 'SOLD'

AND <другие-условия-поиска>

Связи составных ключей

Если одно отношение связано более чем с одним столбцом, используйте ключевое слово AND для разделения каждого условия соединения, как вы делаете в предложении WHERE для множества условий. Возьмем, для примера, таблицу TableA с первичным ключом (PKI, РК2), связанную с таблицей TableB через внешний ключ (FKI, FK2):

SELECT

TableA.COL1,

TableA.COL2,

TableB.COLX,

TableB.COLY

FROM TableA JOIN TableB

ON TableA.PKI = TableB.FKI

AND TableA.PKI = TableB.FK2

WHERE ...

Смешивание неявного и явного синтаксисов

Написание операторов, включающих смешивание неявного и явного синтаксисов, невозможно в Firebird 1.5 и допустимо (но обескураживает) в Firebird 1.0.x. Следующий пример показывает, как не надо писать оператор соединения:

SELECT

Table1.PK,

Table1.COL1,

Table2.PK,

Table2.COLX,

Table3.COLY

FROM Table1, Table2

JOIN Table3 ON TABLE 1. PK = Table3.FK

AND Table3.STATUS = 'SOLD' /* это условие поиска !! */

WHERE Table1.PK = Table2.FK

AND <другие-условия-поиска>

Внешние соединения