Базы Данных - Сибилев, 2007
.pdf181
Выполняя селекцию, исполняющая система на каждой строке F-
таблицы вычисляет значение предиката – условия отбора. Если на текущей строке предикат принял значение FALSE или UNKNOWN, то строка уда-
ляется из рабочего буфера. В результате в буфере остаётся W-таблица, со-
держащая те и только те строки операнда, на которых предикат принял значение TRUE.
Пример 1. Получить всю информацию о поставщиках, имеющих статус выше 90.
SELECT *
FROM S
WHERE St > 90;
В результате обработки предложения FROM в рабочем буфере будет создана неименованная таблица, эквивалентная таблице S (см. приложение А).
Snum |
Snam |
St |
Ci |
S8 |
Владимир |
|
30 Томск |
S2 |
Николай |
50 |
Асино |
|
|
|
|
S5 |
Константин |
100 |
Яя |
|
|
|
|
S4 |
Петр |
20 |
Рио-де-Жанейро |
|
|
|
|
S3 |
Григорий |
80 |
Яя |
|
|
|
|
S9 |
Егор |
100 |
Яя |
|
|
|
|
S7 |
Сергей |
90 |
Асино |
S1 |
Иван |
100 |
Томск |
|
|
|
|
S6 |
Иван |
100 |
Лесото |
|
|
|
|
В процессе обработки предложения будут удалены строки, содержа-
щие в столбце St значения, меньшие или равные 90. Вот результат запро-
са:
Snum |
Snam |
St |
Ci |
S5 |
Константин |
100 |
Яя |
S9 |
Иван |
100 |
Лесото |
S9 |
Егор |
100 |
Яя |
S1 |
Иван |
100 |
Томск |
Пример 2. Получить значения номеров и наименований изделий,
производимых в Томске.
182
SELECT Jnum, Jnam
FROM J
WHERE Ci = ‘Томск’;
Jnum Jnam |
J3 |
дисплей |
J6 |
клавиатура |
Пример 3. Получить значения номеров поставщиков, поставляющих
деталь P1 для изделия J1.
SELECT DISTINCT Snum
FROM SPJ
WHERE Jnum = ‘J1’ AND Pnum = ‘P1’;
SNUM
S8
Пример 4. Получить сведения о поставках, выполненных поставщи-
ками S3, S5, S4, S2.
SELECT *
FROM SPJ
WHERE Snum BETWEEN ‘S2’ AND ‘S5’;
Snum |
Pnum |
Jnum |
Qt |
S2 |
P3 |
J7 |
500 |
S2 |
P9 |
J4 |
200 |
S3 |
P4 |
J8 |
150 |
S3 |
P9 |
J9 |
600 |
S4 |
P4 |
J1 |
130 |
S5 |
P3 |
J8 |
400 |
Рассмотрим теперь более сложные запросы, требующие выборки данных из нескольких таблиц.
7.2.8 Соединения таблиц
Соединения таблиц в SQL2 могут быть реализованы двумя способа-
ми:
− путём использования встроенной операции соединения в предло-
жении FROM;
183
− путём явного указания условий соединения в предикате предложе-
ния WHERE.
Здесь мы обсудим встроенные операции соединения, используемые
в предложении FROM19.
соединение ::= перекрёстное_соединение
| естественное_соединение
| соединение_по_именам_столбцов
| соединение_по_условию
| UNION_соединение
Замечание. Любая из перечисленных структур замещает имя табли-
цы в предложении FROM.
Перекрёстное соединение реализует операцию расширенного пря-
мого произведения РА.
перекрёстное_соединение ::=
таблица_А CROSS JOIN таблица_В
Операцию можно применять к любой паре таблиц схемы. Их совмес-
тимость по взятию расширенного прямого произведения достигается за
счёт уточнения имён полей именами таблиц.
Пример. Пусть в нашей учебной БД существуют следующие реали-
зации таблиц P и J: |
|
Таблица P (Детали) |
Таблица J (Изделия) |
Pnum |
Pnam |
We |
Co |
Ci |
P1 |
корпус |
300 |
белый |
Томск |
P3 |
кнопка |
5 |
красный |
Томск |
P5 |
панель |
100 |
серый |
Асино |
P2 |
разъём |
3 |
чёрный |
Яя |
Jnum |
Jnam |
Ci |
J1 |
процессор |
Асино |
J6 |
клавиатура |
Томск |
J7 |
мышь |
NULL |
P CROSS JOIN J (Перекрёстное соединение)
Pnum |
Pnam |
We |
Co |
P.Ci |
Jnum |
Jnam |
J.Ci |
|
P1 |
корпус |
300 |
белый |
Томск |
J1 |
процессор |
Асино |
|
|
P1 |
корпус |
300 |
белый |
Томск |
J6 |
клавиатура |
Томск |
|
|
P1 |
корпус |
300 |
белый |
Томск |
J7 |
мышь |
NULL |
|
|
P3 |
кнопка |
5 |
красный |
Томск |
J1 |
процессор |
Асино |
|
|
|
|
|
|
|
|
|
|
|
19 Стандарт SQL1 не допускал подобных операций.
184
P3 |
кнопка |
5 |
красный |
Томск |
J6 |
клавиатура |
Томск |
P3 |
кнопка |
5 |
красный |
Томск |
J7 |
мышь |
NULL |
P5 |
панель |
100 |
серый |
Асино |
J1 |
процессор |
Асино |
P5 |
панель |
100 |
серый |
Асино |
J6 |
клавиатура |
Томск |
P5 |
панель |
100 |
серый |
Асино |
J7 |
мышь |
NULL |
P2 |
разъём |
3 |
чёрный |
Яя |
J1 |
процессор |
Асино |
P2 |
разъём |
3 |
чёрный |
Яя |
J6 |
клавиатура |
Томск |
P2 |
разъём |
3 |
чёрный |
Яя |
J7 |
мышь |
NULL |
Никакого семантического значения этот набор данных не имеет. Как правило, он используется для построения других таблиц. Заметим, что предложения FROM A, B и FROM A CROSS JOIN B эквивалентны, т.е.
производят временные таблицы, совпадающие с точностью до порядка строк.
Операция естественного соединения в SQL может быть реализова-
на в четырёх разновидностях.
естественное_соединение ::=
таблица_А [NATURAL] [тип_соединения] JOIN таб-
лица_В
тип_соединения ::= INNER | {{LEFT | RIGHT | FULL} [OUTER]}
Ключевое слово NATURAL смысловой нагрузки не несёт и может быть опущено. Соединяемые таблицы должны иметь одноимённые столб-
цы одного типа и одинаковой длины.
Естественное соединение может быть внутренним (INNER) или
внешним (OUTER). По умолчанию используется INNER.
Операция INNER JOIN производит аналог естественного соедине-
ния РА. Производная таблица содержит все столбцы операндов. Одно-
имённые столбцы включаются однократно. Строками производной табли-
цы являются объединения таких строк операндов, в которых значения всех
одноимённых столбцов совпадают.
Пример. Получим в условиях предыдущего примера таблицу, со-
держащую сведения о парах деталей и изделий, размещённых в одном и том же городе:
185
P INNER JOIN J (Внутреннее естественное соединение)
Pnum |
Pnam |
We |
Co |
Ci |
Jnum |
Jnam |
P5 |
панель |
100 |
серый |
Асино |
J1 |
Процессор |
P3 |
кнопка |
5 |
красный |
Томск |
J6 |
Клавиатура |
P1 |
корпус |
300 |
белый |
Томск |
J6 |
Клавиатура |
В этой таблице отсутствуют сведения о детали P2 и изделии J7, так как описывающие их строки не имеют пар по столбцу Ci в таблицах J и P
соответственно.
Однако в практике применения БД нередко встречаются запросы,
предполагающие отображение всех строк одной таблицы совместно с су-
ществующими парными строками другой. В реляционной алгебре нет опе-
рации, обеспечивающей построение таких запросов.
Пример. Пусть необходимо получить полные сведения обо всех де-
талях и об изделиях, размещенных в тех же городах. Как мы видели, ре-
зультат операции INNER JOIN не содержит всех ожидаемых данных.
Нужная таблица может быть построена с помощью операции внешнего
(OUTER) соединения, например, левого (LEFT).
P LEFT OUTER JOIN J (Левое внешнее соединение)
Pnum |
Pnam |
We |
Co |
Ci |
Jnum |
Jnam |
P1 |
корпус |
300 |
белый |
Томск |
J6 |
Клавиатура |
P2 |
разъём |
3 |
чёрный |
Яя |
NULL |
NULL |
P3 |
кнопка |
5 |
красный |
Томск |
J6 |
Клавиатура |
P5 |
панель |
100 |
серый |
Асино |
J1 |
Процессор |
Аналогично этому, все сведения об изделиях и о деталях, размещён-
ных в тех же городах, можно получить с помощью операции правого
(RIGHT) внешнего соединения.
P RIGHT OUTER JOIN J (Правое внешнее соединение)
Pnum |
Pnam |
We |
Co |
Ci |
Jnum |
Jnam |
P5 |
панель |
100 |
серый |
Асино |
J1 |
Процессор |
P3 |
кнопка |
5 |
красный |
Томск |
J6 |
клавиатура |
P1 |
корпус |
300 |
белый |
Томск |
J6 |
клавиатура |
NULL |
NULL |
NULL |
NULL |
NULL |
J7 |
Мышь |
Легко убедиться в том, что один и тот же результат можно получить как с помощью правого, так и с помощью левого внешнего соединения.
186
Например, выражения J RIGHT JOIN P и P LEFT JOIN J определяют эк-
вивалентные таблицы.
Стандарт SQL2 допускает реализацию так называемого полного
(FULL) внешнего соединения, которое можно понимать как теоретико-
множественное объединение левого и правого внешних соединений.
Пример. Пусть нам нужны сведения обо всех деталях и изделиях с указанием пар деталей и изделий, размещенных в одном и том же городе.
Требуемый результат можно получить с помощью следующей операции: P FULL OUTER JOIN J (Полное внешнее соединение)
Pnum |
Pnam |
We |
Co |
Ci |
Jnum |
Jnam |
NULL |
NULL |
NULL |
NULL |
NULL |
J7 |
Мышь |
P1 |
корпус |
300 |
белый |
Томск |
J6 |
Клавиатура |
P2 |
разъём |
3 |
чёрный |
Яя |
NULL |
NULL |
P3 |
кнопка |
5 |
красный |
Томск |
J6 |
Клавиатура |
P5 |
панель |
100 |
серый |
Асино |
J1 |
Процессор |
Приведём алгоритмическое определение операции полного внеш-
него соединения.
1.Вычислить внутреннее соединение.
2.Для каждой строки левой таблицы, если она не представлена во внутреннем соединении, вычислить строку соединения, заполнив столбцы,
соответствующие левой таблице, значениями текущей строки, а столбцы,
соответствующие правой таблице, NULL-значениями.
3. Для каждой строки правой таблицы, если она не представлена во внутреннем соединении, вычислить строку соединения, заполнив столбцы,
соответствующие правой таблице, значениями текущей строки, а столбцы,
соответствующие левой таблице, NULL-значениями.
4.Добавить результаты шагов 2 и 3 к результату шага 4.
5.Определения левого и правого внешних соединений можно полу-
чить из вышеприведённого, опустив шаг 3 или 2 соответственно.
UNION-соединение можно трактовать как реляционную разность [2,
с. 73] полного внешнего и внутреннего соединений. Синтаксис операции следующий:
187
UNION_соединение ::= таблица_А UNION JOIN таблица_В
Пример. Сведения о деталях, размещённых в городах, в которых не
размещено ни одно изделие, и об изделиях, размещённых в городах, в ко-
торых не размещена ни одна деталь, можно получить с помощью следую-
щей операции:
P UNION JOIN J (UNION-соединение)
Pnum |
Pnam |
We |
Co |
Ci |
Jnum |
Jnam |
NULL |
NULL |
NULL |
NULL |
NULL |
J7 |
мышь |
P2 |
разъём |
3 |
чёрный |
Яя |
NULL |
NULL |
Во всех модификациях естественного соединения сравниваются на-
боры значений всех одноимённых столбцов в строках соединяемых таблиц.
В ряде случаев это может привести к недоразумениям.
Пример. Пусть в нашей БД существует следующая таблица, храня-
щая сведения о поставках деталей для изделий:
Таблица SPJ (Поставки)
Snum |
Pnum |
Jnum |
Qt |
S1 |
P1 |
J6 |
100 |
S1 |
P2 |
J6 |
1877 |
|
|
|
|
и пусть нам нужны сведения о конкретных деталях, поставляемых для конкретных изделий. Если мы для получения этих сведений используем естественное соединение таблиц P, J и SPJ, то результатом будет следую-
щая таблица:
P INNER JOIN J INNER JOIN SPJ
Pnum |
Pnam |
We |
Co |
Ci |
Jnum |
Jn |
Snum |
Qt |
P1 |
корпус |
300 |
белый |
Томск |
J6 |
клавиатура |
S1 |
100 |
Результат не содержит всех ожидаемых сведений. Утрачены данные о поставке детали P2. Это произошло потому, что соединения выполнялись по столбцам Pnum, Jnum, Ci. На самом деле соединение по столбцу Ci не нужно.
188
Операция соединения по именам столбцов использует в качестве аргумента список имён столбцов, по которым должно выполняться соеди-
нение.
соединение_по_именам_столбцов ::=
таблица_А [тип_соединения] JOIN таблица_В
USING (имя_столбца.,..)
Как и естественное соединение, эта операция применяется к табли-
цам, имеющим одноимённые столбцы одного типа и одинаковой длины.
Однако соединение выполняется по признаку совпадения значений под-
множества одноимённых столбцов, указанного списком после ключевого слова USING. Допустимы все определённые выше типы соединения.
Пример. В условиях предыдущего примера правильное выражение соединения может быть таким:
(P INNER JOIN SPJ) INNER JOIN J USING (Jnum)
или таким:
P INNER JOIN (SPJ INNER JOIN J) USING (Pnum)
Эти выражения произведут таблицу, эквивалентную показаной ниже.
Pnum |
Pnam |
We |
Co |
P.Ci |
Snum |
Jnum |
Qt |
Jn |
J.Ci |
|
|
|
|
|
|
|
|
|
|
P1 |
корпус |
300 |
белый |
Томск |
S1 |
J6 |
100 |
Клавиатура |
Томск |
|
|
|
|
|
|
|
|
|
|
P2 |
разъём |
3 |
чёрный |
Яя |
S1 |
J6 |
1877 |
Клавиатура |
Томск |
|
|
|
|
|
|
|
|
|
|
Операция соединения по условию использует следующий синтак-
сис:
соединение_по_условию ::=
таблица_А [тип_соединения] JOIN таблица_В
ON предикат
предикат – логическое выражение, содержащее ссылки на столбцы соединяемых таблиц и принимающее значения TRUE, FALSE или
UNKNOWN (см. п. 7.2.6). Значение предиката вычисляется на значениях
189
ссылочных столбцов в строке расширенного прямого произведения таблиц
(строке-кандидате соединения).
Соединяемые таблицы должны иметь сравнимые столбцы. Произво-
димая таблица включает все столбцы обоих операндов, а состав её строк зависит от типа соединения.
Внутреннее (INNER) соединение можно рассматривать как реализа-
цию операции соединения по условию РА. Оно производит только такие конкатенации строк операндов, на которых предикат принимает значение
TRUE.
Пример. Для того чтобы получить сведения о деталях и изделиях,
размещённых в различных городах, следует использовать операцию внут-
реннего соединения по условию P.Ci <> J.Ci: P INNER JOIN J ON P.Ci <> J.Ci
Pnum |
Pnam |
We |
Co |
P.Ci |
Jnum |
Jn |
J.Ci |
P1 |
корпус |
300 |
белый |
Томск |
J1 |
процессор |
Асино |
P2 |
разъём |
3 |
чёрный |
Яя |
J1 |
процессор |
Асино |
P3 |
кнопка |
5 |
красный |
Томск |
J1 |
процессор |
Асино |
P2 |
разъём |
3 |
чёрный |
Яя |
J6 |
клавиатура |
Томск |
P5 |
панель |
100 |
серый |
Асино |
J6 |
клавиатура |
Томск |
Определения внешних соединений по условию аналогичны опреде-
лениям естественных внешних соединений. Сформулируйте их самостоя-
тельно.
Читатель легко убедится в том, что в условиях рассматриваемого примера соединение P LEFT JOIN J ON P.Ci <> J.Ci совпадает с внутрен-
ним. Соединение P RIGHT JOIN J ON P.Ci <> J.Ci будет содержать до-
полнительную строку – сведения об изделии J7.
Понятие соединения в SQL2 шире аналогичного понятия в классиче-
ской реляционной алгебре. Определяя внешние соединения и соединения
USING и UNION, авторы стандарта руководствовались потребностями практического применения языка. Действительно, как мы увидим далее,
190
использование встроенных операторов соединения позволяет значительно упростить логику запросов на выборку данных.
7.2.9 Запросы с соединениями таблиц
В общем случае первые три предложения оператора выборки данных выполняют комбинацию операций соединения, селекции и проекции20.
Многие распространённые в настоящее время программные продук-
ты не поддерживают встроенные операции соединения. Входные языки этих СУБД обеспечивают возможность указания соответствующих усло-
вий в предикате предложения WHERE. Однако наиболее «продвинутые» системы допускают оба варианта определения соединений. В нижесле-
дующих примерах для каждого запроса приводится, по крайней мере, две эквивалентных формулировки, иллюстрирующих оба способа.
Пример 1. Получить значения наименований изделий, для которых выполняет поставки поставщик S1.
Источником данных для этого запроса служат таблицы J и SPJ. Все-
гда можно использовать, по меньшей мере, два подхода к проектированию оператора выборки.
Встиле РИ: «Получить значения атрибута Jnam из таких кортежей отношения J, для которых в отношении SPJ существуют кортежи с теми же значениями атрибута Jnum и значениями атрибута Snum, равными S1.»
Встиле РА: «Выполнить проекцию на атрибут Jnam селекции по условию Snum = ‘S1’ естественного соединения таблиц J и SPJ.»
Первый (возможно, наиболее естественный) подход мы рассмотрим в п. 7.2.12.
Второй подход приводит к следующим сответствующим SQL2 фор-
мулировкам:
Вариант 1
SELECT DISTINCT Jnam
20 Иногда эту последовательность операций называют операцией отображения.