Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Информационное обеспечение систем управления. Построение запросов пр.pdf
Скачиваний:
4
Добавлен:
15.11.2022
Размер:
3.76 Mб
Скачать

Город

Аэропорт

Москва

Быково

Москва

Внуково

Москва

Домодедово

Москва

Шереметьево

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

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

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

Таблицу в соединении будем называть левой, если она стоит перед ключевым словом JOIN (слева), и правой, если она стоит по­ сле от него (справа).

Левое внешнее соединение

LEFT (OUTER) - тип соединения «левое (внешнее)». Левое со­ единение таблиц включает в себя все строки из левой таблицы и те строки из правой таблицы, для которых выполняется условие со­ единения. Для строк из левой таблицы, для которых не найдено со­ ответствия в правой, в столбцы, извлекаемые из правой таблицы, заносятся значения NULL.

Левое внешнее соединение чаще всего используется в наших операторах по причине его естественности. Итак найдем все аэро­ порты, даже если код города, в котором он находится, не указан.35

SELECT C.CT_NAME AS "Город”,

A.APJNAME AS "Аэропорт"

FROM AIRPORT A LEFT OUTER JOIN CITY C

ON A.AP_CT__CODE = C.CT_CODE

ORDER BY C.CTJNAME, A.AP NAME

Получаем:

Листинг 17

Результат левого внешнего объединения таблиц AIROPORT

иCITY - список всех аэропортов с указанием города

втом случае, если аэропорт располагается в городе

Город

Аэропорт

Екатеринбург

Кольцово

Москва

Быково

Москва

Внуково

Москва

Домодедово

Москва

Шереметьево

Пермь

Савино

Санкт-Петербург

Пулково

NULL

Аэропорт Н-ской ВЧ

Вначале отбираются строки первой, «главной», таблицы на ос­ новании условий, заданных в предложении WHERE. Затем к вы­ бранным строкам добавляются данные из второй, присоединяемой, таблицы в соответствии с условиями соединения, заданными в предложении ON. Особенностью внешних соединений является то, что в выходной набор данных попадают и те строки, которые содержат пустые значения (NULL) в тех столбцах главной таблицы, которые присутствуют в условии соединения в предложении ON. В нашем случае в результат попала строка

Аэропорт Н-ской ВЧ, NULL

Мы видим аэропорт, для которого код города не указан (этот аэропорт не находится ни в одном из известных городов).

Продемонстрированное левое внешнее соединение позволяет получить список аэропортов, находящихся вне города, для этого необходимо отобрать только те строки, где поля из таблицы CITY

будут содержать пустые значения (NULL).

Отбираем эти строки

при помощи предложения WHERE.36

 

SELECT C.CT_NAME

AS

"Город",

 

A.APJNAME

AS

"Аэропорт"

FROM AIRPORT A

LEFT OUTER

JOIN CITY C

ON A.AP_CT_CODE = C.CT_CODE

WHERE C.CT_CODE IS NULL

Получаем только одну строку:

Город

А эропорт

NULL

Аэропорт Н-ской ВЧ

 

Правое внешнее соединение

RIGHT (OUTER) - тип соединения «правое (внешнее)». Правое соединение таблиц включает в себя все строки из правой таблицы и те строки из левой таблицы, для которых выполняется условие соединения. Для строк из правой таблицы, для которых не найдено соответствия в левой, в столбцы, извлекаемые из левой таблицы, заносятся значения NULL.

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

Для иллюстрации этой зеркальности выполните оператор:37

SELECT C.CT_NAME AS

"Город",

A .A PN A M E AS

"Аэропорт"

FROM AIRPORT A RIGHT OUTER JOIN CITY C

ON A.AP_CT_CODE = C.CT_CODE

ORDER BY C.CTJNAME, A.AP NAME

Теперь мы получим список из всех городов, если в городе име­ ется аэропорт, он будет представлен в соответствующем столбце, если аэропорта нет - столбец будет содержать пустые значения (NULL):

Листинг 18

Результат правого внешнего объединения таблиц AIROPORT

иCITY - список всех городов с указанием аэропортов

втом случае, если в этом городе есть аэропорты

Город

Аэропорт

Екатеринбург

Кольцово

Москва

Быково

Москва

Внуково

Москва

Домодедово

Москва

Шереметьево

Пермь

Савино

Санкт-Петербург

Пулково

Чайковский

NULL

В получившейся список попала строка

| Чайковский

| NULL

|

Мы получили город Чайковский, в котором в настоящее время уже нет аэропорта.

Полное внешнее соединение

FULL (OUTER) - тип соединения «полное (внешнее)». Это комбинация левого и правого соединений. В полное соединение включаются все строки из обеих таблиц. Для совпадающих строк поля заполняются реальными значениями, для несовпадающих строк поля заполняются в соответствии с правилами левого и пра­ вого соединений. На практике этот тип соединения требуется чрез­ вычайно редко. Поэтому примеров мы не приводим.

Более сложные примеры соединений

Количество выполняемых соединений таблиц в одном операто­ ре SELECT не имеет физических ограничений, однако рекоменду­ ется использовать не более 16.

Рассмотрим пример двойного внешнего соединения, т.е. тот случай, когда к первой таблице присоединяется не одна, а уже две таблицы.

Чтобы увидеть фамилии с именами и отчествами всех членов экипажа с указанием их роли, номера авиалинии и даты вылета, нужно выполнить два соединения таблицы EQUIPAGE с таблицей PERSON и с таблицей RANK.

Введите и выполните оператор38:

SELECT E.EQJFLJDATE AS "Дата вылета",

E.EQJFL NUM AS "Авиалиния",

P.PR_NAME2

|| " || P.PRJNAME3 || " || P.PR_NAME

AS "ФИО",

 

R.RNK_NAME AS "Роль"

FROM EQUIPAGE

E INNER JOIN PERSON P

ON E.EQ_PR_CODE = P.PR_CODE INNER JOIN RANKR

ON E.EQ_RNK_CODE = R.RNK_CODE

WHEREE.EQ_FL_DATEBETWEEN 4.02.08' AND '29.02.08' ORDER BY E.EQ FLJDAТЕ, E.EQ_FL_NUM, 3

Вначале отбираются все члены экипажа из таблицы EQUIPAGE (здесь она становится главной) на основании условий предложения WHERE (все рейсы за февраль 2008 г.). В выбранные строки добавляются полные имена из таблицы PERSON. Условием соединения является равенство кода в таблице PERSON коду чело­ века в таблице EQUIPAGE. После чего к этим строкам добавляются названия роли из таблицы RANK. Здесь условием соединения явля­ ется равенство кода, первичного ключа таблицы RANK коду роли в начальной, «главной», таблице EQUIPAGE. Результат сортируем по дате вылета, номеру авиалинии и фамилиям, именам и отчествам (т.к. поле «ФИО» вычисляется, в списке сортировки указываем номер поля).

В результате выполнения двойного соединения мы получим:

Листинг 19

Двойное внешнее соединение - список всех членов экипажа с указанием их роли, номера авиалинии и даты вылета

Дата вылета

Авиалиния

ФИО

Роль

13.02.2008

901

Анна Валерьевна Грунтович

Бортпроводник

13.02.2008

901

Евгений Андреевиич Болотов

Командир

13.02.2008

901

Людмила Александровна Блинова

Бортпроводник

13.02.2008

901

Марина Владимировна Волченко

Бортпроводник

13.02.2008

901

Наталья Николаевна Васюкова

Бортпроводник

13.02.2008

901

Павел Павлович Попутько

Пилот

14.02.2008

901

Анна Евгеньевна Елизарова

Бортпроводник

14.02.2008

901

Вера Раисовна Дударева

Бортпроводник

14.02.2008

901

Екатерина Викторовна Еремеева

Бортпроводник

14.02.2008

901

Елена Ильинична Жукова

Бортпроводник

14.02.2008

901

Семен Валерьевич Дудин

Командир

14.02.2008

901

Юлий Альбертович Алексеев

Пилот

15.02.2008

901

Анна Валерьевна Грунтович

Бортпроводник

15.02.2008

901

Евгений Андреевнич Болотов

Командир

15.02.2008

901

Елена Анатольевна Мичурина

Бортпроводник

15.02.2008

901

Марина Владимировна Волченко

Бортпроводник

15.02.2008

901

Сергей Иванович Ридель

Пилот

15.02.2008

901

Татьяна Александровна Соснина

Бортпроводник

Необходимо отметить, что порядок указания соединяемых таб­ лиц не имеет значения. Здесь важно задать первую, «главную», таб­ лицу сразу после ключевого слова FROM, все остальные соединяе­

мые таблицы «подключаются» к строкам, выбранным

именно

из этой таблицы, и ее строки выбираются на основании

условия

в предложении WHERE.

Для иллюстрации этого изменим предыдущий оператор SELECT, поменяв местами соединяемые таблицы. Выполните опе­

ратор:

SELECT E.EQ_FL_DATE AS "Дата вылета", E.EQJFLJNUM AS "Авиалиния",

P.PR NAME2 || " || P.PRJNAME3 || " || P.PR_NAME AS "ФИО",

R. RNK_NAME AS "Роль"

FROM PERSON P INNER JOIN EQUIPAGE E

ON E.EQJPR_CODE = P.PR_CODE INNER JOIN

RANKR

ON E.EQ_RNK_CODE - R.RNK_CODE WHEREE.EQ_FL_DATEBETWEEN '1.02.08'AND '29.02.08' ORDER BY E.EQ_FL_DAТЕ, E.EQJFLJNUM, 3

В качестве главной таблицы мы задали таблицу PERSON, в ре­ зультате получим точно такой же список, как и в предыдущем слу­ чае.

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

SELECT T.TR_AL_NUM AS "Номер Авиалинии",

ATO.APJNAME AS "Аэропорт прилета",

S.SL_NAME AS "Салон",

T.TR_COSTAS "Стоимость" FROM TARIFF T

INNER JOIN AIRPORT AFROM ON (T. TR_AP_FROM =

AFROM.AP_CODE)

INNER JOIN AIRPORT ATO ON (T.TR_AP_TO =

ATO.AP_CODE)

INNER JOIN SALON S ON (T. TR_SL_ TYPE = S.SL_TYPE)

INNER JOIN CITY C ON (AFROM.AP_CT_CODE =

C.CT_CODE)

WHERE C.CTJNAME = 'Пермь'

Таким образом, в запросе будут задействованы следующие таблицы: TARIFF, AIRPORT, SALON, CITY. Обратите внимание, что таблица AIRPORT используется в запросе два раза - один раз мы применяем соединение, используя поле TR_AP_TO таблицы TARIFF, таблица в этом соединении обозначается псевдонимом АТО и аэропорт прилета, второй раз в соединении используется по­ ле TR_AP_FROM, в этом случае таблица AIRPORT будет обозна­ чаться псевдонимом AFROM и означать аэропорт вылета.

Следующий пример потребует объединения шести таблиц. По­ лучим список (фамилию, имя, отчество) тех, кто имеет билеты из Перми в Москву на 11.01.2008, кроме ФИО выведем вид салона, стоимость билета и занимаемое место. В запросе мы должны свя­ зать следующие таблицы: PERSON связываем с таблицей TICKET, TICKET - с TARIFF, TARIFF - с SALON, далее TARIFF дважды связываем с AIRPORT (первый раз связываем используя поле TR AP FROM, т.е. определяя аэропорт вылета, второй раз связыва­ ем используя поле TR AP TO, тем самым будет определен аэро­ порт прилета), AIRPORT дважды связывается с CITY (один раз - для города, где размещен аэропорт вылета, второй раз связь будет определять город, где размещен аэропорт прилета). Поскольку таб­ лицы AIRPORT и CITY используются два раза, для них использу­ ются различные синонимы.

Приводим вид запроса:39

SELECT PR NAME2 AS "Имя",

PR NAME3 AS "Отчество",

PRJNAME AS "Фамилия", S.SL_NAME AS "Салон", ТС. TC_SEAТ AS "Место",

TR.TR_COSTAS "Стоимость" FROM PERSON P

INNER JOIN TICKET TC ON TC. TC_PR_CODE = P.PR_CODE

INNER JOIN TARIFF TR ON TR. TR_CODE =

TC.TC_TR_CODE

INNER JOIN SALON S ON TR. TR_SL_TYPE = S.SL_TYPE INNER JOIN AIRPORTAFROM ON AFROM.AP_CODE =

TR. TR_AP_FROM

INNER JOIN CITY CFROM ON CFROM.CT_CODE =

AFROM.AP_CT_CODE

INNER JOIN AIRPORTATO ON ATO.AP_CODE =

TR.TR_AP_TO

INNER JOIN CITY CTO ON CTO.CT_CODE =

ATO.AP_CT_CODE

WHERE CFROM. CT_NAME = 'Пермь'AND CTO. CTJNAME

AND TO. TC_FL_DATE = 41.01.2008'

Получаем список:

Листинг 20

Список купивших билеты из Перми в Москву на 11.01.2008, объединение шести таблиц

Имя

Отчество

Фамилия

Салон

Место

Стоимость

Ирина

Валентиновна

Щекина

Бизнес

8800

Константин

Игоревич

Баталов

Бизнес

8800

Ольга

Юрьевна

Боброва

Бизнес

8800

Елена

Павловна

Бельтюкова

Бизнес

8800

Светлана

Леонидовна

Верушкина

Бизнес

8800

Александр

Александрович

Чудинов

Бизнес

8800

Сергей

Владимирович

Богатырев

Бизнес

8800

Владимир

Николаевич

Карпов

Бизнес

ЗБ

8800

Татьяна

Викторовна

Владысик

Бизнес

ЗГ

8800

Наталья

Васильевна

Вожакова

Бизнес

8800

Владимир

Юрьевич

Войтович

Бизнес

8800

Елена

Александровна

Воронюк

Эконом

20А

3500

Мария

Ивановна

Выгузова

Эконом

20Б

3500

Ольга

Николаевна

Вяткина

Эконом

20В

3500

Юлия

Дмитриевна

Гаевская

Эконом

20Г

3500

Василий

Александрович

Глазов

Эконом

20Д

3500

Дмитрий

Федорович

Глумов

Эконом

21А

3500

1

 

 

 

 

 

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

Введем запрос:40

SELECT AC .A CN AM E

AS

“Авиакомпания

SUM( TRF.TR_COST)

AS

“Стоимость”

FROM TARIFF TRF

 

 

INNER JOIN TICKET TC ON (TRF. TR_CODE =

TC.TC_TR_CODE)

INNER JOIN AIRLINE AL ON (TRF. TR_ALJNUM = AL.ALNUM )

INNER JOIN AIRCOMPANYAC ON (AL.AL_AC_CODE =

AC.AC_CODE) GROUP BY AC.ACJNAME

ORDER BY 2

В результате получим список:

Листинг 21

Результат объединения и группировки, суммарная стоимость проданных за 2008 г. билетов для каждой из авиакомпаний

Авиакомпания

Стоимость

S7 Airlines

42100

Lufthansa

57800

Сибавиатраис

59420

Ютэйр-экспресс

80300

Sky express

19690

Аэрофлот-РА

126800

Рефлексивное соединение, или самосоединение

Соединяемые таблицы не обязательно должны отличаться от главной таблицы в операторе SELECT. Если таблица соединяется сама с собой, то такое соединение называется рефлексивным или самосоединением. Есть еще один термин для такого соединения — реентерабельное. Рефлексивное связывание удобно использовать, когда все необходимые данные размещаются в одной таблице, но требуется каким-то образом сравнить одни записи таблицы с дру­ гими.

Найдем всех однофамильцев, т.е. выведем фамилии (с именами

иотчествами) и даты рождения из таблицы PERSON, если сущест­ вует соединение с этой же самой таблицей. Соединяем по фамилии,

ичтобы все строки не соединились сами с собой, нужно указать, что первичные ключи (PR_CODE) для двух соединенных строк несовпадают.41

SELECT DISTINCT

P2.PRJNAME

||

|| Р2.PRJNAМЕ2 ||

||

P2.PRJNAME3 AS "ФИО",

 

 

P2.PRJBIRTHDAYAS "Дата рождения"

 

FROM PERSON Р2

INNER JOIN PERSON P1 ON

 

(P2.PR_NAME = P1 .PRJNAME) AND (P2.PR_CODE о P1.PR_CODE)

ORDER BY 1

Если в исходной таблице есть больше чем два человека с одной фамилией, мы получим дублирование строк, поэтому используем DISTINCT для исключения дубликатов. Результат упорядочиваем по вычисляемому полю ФИО, чтобы сразу увидеть группы однофа­ мильцев.

Листинг 22

Результат самообъединения таблицы PERSON с самой собой - список всех однофамильцев

ФИО

Дата рождения

Блинова Людмила Александровна

28.08.1957

Блинова Ольга Владимировна

 

Блинова Светлана Александровна

05.05.1980

Васильева Марианна Юрьевна