Скачиваний:
122
Добавлен:
02.05.2014
Размер:
2.3 Mб
Скачать

7.7.11. Определить имена поставщиков по крайней мере одной красной детали

SELECT DISTINCT S.SNAME FROM S WHERE S.St IN

( SELECT SP.Si FROM SP WHERE SP.PI = IN ( SELECT P.PI FROM P

WHERE P.COLOR = 'Red' ) ) ; Подзапросы могут иметь произвольную глубину вложения.

Упражнение. Приведите эквивалентную формулировку этого запроса с использова­нием операции соединения.

7.7.12. Указать номера поставщиков, статус которых меньше текущего максимального статуса

в таблице S

SELECT S.S# FROM S

WHERE S.STATUS <

( SELECT MAX ( S.STATUS ) FROM S ) ;

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

7.7.13. Указать имена поставщиков детали с номером 'р2'

Замечание. Этот пример повторяет пример 7.7.10. Ниже приводится другое решение для того, чтобы представить еще одно средство языка SQL.

SELECT DISTINCT S.SNAME FROM S WHERE EXISTS ( SELECT * FROM SP

WHERE SP.S# = S.S# AND SP.P# = 'P2' ) ;

Пояснение. SQL-выражение EXISTS (SELECT ... FROM ...) будет иметь значение исти­на тогда и только тогда, когда результат вычисления выражения SELECT ... FROM ... будет непустым. Другими словами, в языке SQL функция EXISTS соответствует квантору существования реляционного исчисления [18.6].

Замечание. В этом SQL-примере ссылка на подзапрос представлена как ссылка на относительный подзапрос, поскольку в данном подзапросе содержится ссылка на пере­менную кортежа, а именно — на неявную переменную кортежа S, которая определена во внешнем запросе. Другим примером относительного подзапроса служит пример 7.7.8.

7.7.14. Выбрать имена поставщиков, которые не поставляют деталь с номером 'р2'

SELECT DISTINCT S.SNAME FROM S

WHERE NOT EXISTS ( SELECT * FROM SP

WHERE SP.SI = S.St AND SP.PI = 'P2' ) j

Этот же запрос можно представить в альтернативной формулировке.

SELECT DISTINCT S.SNAME FROM S

WHERE S.SI NOT IN ( SELECT SP.SI FROM SP

WHERE SP.Pf = 'P2' ) ;

7.7.15. Определить имена поставщиков всех типов деталей

SELECT DISTINCT S.SNAME FROM S

WHERE NOT EXISTS { SELECT * FROM P

WHERE NOT EXISTS

( SELECT *

FROM SP

WHERE SP.SI

AND SP.PI

S.SI

p.Pi ) ) ;

Язык SQL не включает какой-либо непосредственной поддержки универсального квантора FORALL; следовательно, запросы типа "ДЛЯ ВСЕХ" обычно выражаются через отрицание кванторов существования, как в этом примере.

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

SELECT DISTINCT S.SNAME FROM S

WHERE ( SELECT COUNT ( SP.Pt ) FROM SP

WHERE SP.Si = S.St ) = ( SELECT COUNT ( P.Pt ) FROM P ) ;

(Расшифровка: "Получить имена поставщиков, для которых количество поставляе­мых деталей равно количеству всех деталей",) Однако обратите внимание на следующие обстоятельства.

  • Во-первых, в отличие от формулировки с выражением NOT EXISTS, в последней формулировке предполагается, что в отношении SP нет номеров деталей, которые не содержатся в отношении Р. Другими словами, эти две формулировки эквива­лентны (а вторая будет верной) только в случае соблюдения определенного огра­ничения целостности (подробности приводятся в следующей главе).

  • Во-вторых, метод, примененный во второй формулировке для сравнения двух ко­личеств (подзапросы, расположенные по обе стороны знака равенства), изначаль­но не поддерживался в языке SQL и был добавлен только в стандарте SQL/92. Он все еще не поддерживается во многих продуктах.

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

SELECT DISTINCT S.SNAME FROM S

WHERE ( SELECT SP.Pt ) FROM SP

WHERE SP.St = S.St ) = ( SELECT P.Pt FROM P ) ;

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

Соседние файлы в папке Дейт К. Дж. Введение в системы баз данных [7 издание]