Шрифт:
Рис. 22.4. Полное соединение
Вот оператор, использующий те же входные потоки, что и наш пример INNER JOIN:
SELECT
Table1.PK,
Table1.COL1,
Table2.PKX,
Table2.COLX
FROM Table1 FULL JOIN Table2
ON Table1.PK = Table2.FK
WHERE ... <условия-поиска>
На рис. 22.4 показано, как будут объединены потоки для полного соединения.
Перекрестные соединения
Firebird не поддерживает языковых элементов для перекрестного соединения (CROSS JOIN), которое создает набор данных, являющийся декартовым произведением двух таблиц. То есть для каждой строки левого потока выходной поток будет содержать каждую строку из правого потока. В редких случаях, когда вам нужно декартово произведение, вы можете использовать синтаксис SQL-89 без каких-либо критериев соединения в предложении WHERE, например:
SELECT T1.*, Т2.* FROM T1 TABLE1, T2 TABLE2;
Обработчик запросов Firebird иногда внутренне создает перекрестные соединения, когда конструирует "реки" в процессе соединения операций (см. разд. "Темы оптимизации" этой главы).
Естественные соединения
Firebird не поддерживает естественное соединение (NATURAL JOIN), также известное как эквисоединение (EQUI JOIN), которое создает набор данных, связывая два потока на основе соответствия столбцов, использующих общие идентификаторы столбцов с одинаковыми значениями. В Firebird вы всегда должны указывать условия соединения.
Двусмысленность в запросах JOIN
В различных книгах по теории баз данных сказано, что двусмысленность может существовать, только когда некоторые имена столбцов появляются в нескольких потоках. Человек, практически работающий с базами данных, может рассказать другую историю. Вопрос устранения двусмысленности отпадает в зависимости от способа, каким сервер базы данных реализует синтаксический разбор, создание потоков и сортировку, которые выполняются в процессе операции соединения.
InterBase был снисходителен к отклонениям от недвусмысленности в синтаксисе соединений - иногда с неудачными результатами. Если вы переносите существующий код вашего приложения, работавшего с InterBase, не пугайтесь исключений SQL, которые выдаст Firebird в процессе первого тестового выполнения запросов с соединениями. Он покажет вам места в вашем коде, где раньше допускалось выполнение запросов, которые могли возвращать неверные результаты.
Firebird не примет запросы соединения, содержащие ссылки на столбцы, которые не имеют полного квалификатора таблицы. Квалификатор таблицы может быть идентификатором таблицы или алиасом таблицы. Начиная с версии 1.5 недопустимо их смешивать. Если вы используете версию 1.0, будьте последовательны, если хотите избежать переписывания кода при переходе на новые версии.
Предыдущие примеры использовали идентификаторы таблиц. Использование алиасов таблиц более элегантно и компактно, а для некоторых запросов (см. разд. "Реентерабельные соединения") является обязательным.
Алиасы таблиц
Если имя таблицы длинное или запутанное, или если существует много таблиц, использование алиасов таблиц будет полезным (и в некоторых случаях необходимым) для большей ясности операторов. Обработчик запроса трактует алиас таблицы как синоним таблицы, которую алиас представляет. Алиасы таблиц обязательны в запросах, которые формируют множество потоков из одной и той же таблицы.
! ! !
СОВЕТ. В базе данных диалекта 3, которая была создана с использованием ограниченных идентификаторов (delimited identifiers), комбинированных с символами в нижнем регистре или при смешивании регистров в именовании объектов и/или с использованием "неправильных символов", написание запросов может стать довольно утомительным занятием, часто порождающим ошибки, если не используются алиасы.
. ! .
Алиас может быть использован везде, где он допустим для обозначения имени таблицы, как квалификатор; имена всех таблиц должны быть заменены на алиасы. Смешивание идентификаторов таблиц с алиасами в одном и том же запросе приведет к исключениям в Firebird 1.5 и следующих версиях.
Следующий пример использует идентификаторы таблиц:
SELECT
TABLEA.COL1,
TABLEA.COL2,
TABLEB.COLB,
TABLEB.COLC,
TABLEC.ACOL
FROM TABLEA
JOIN TABLEB ON TABLEA.COL1 = TABLEB.COLA
JOIN TABLEC ON TABLEB.COLX = TABLEC.BCOL
WHERE TABLEA.STATUS = 'SOLD'
AND TABLEC.SALESMAN_ID = '44'
ORDER BY TABLEA.COL1;
Тот же пример, использующий алиасы:
SELECT
A.COL1,