Подзапросы и структурированные запросы
Подзапрос – дополнительный метод манипулирования несколькими таблицами. Другими словами, это инструкция SELECT, вложенная:
· в предложение WHERE, HAVING или SELECT;
· в инструкцию INSERT, UPDATE или DELETE;
· в другой подзапрос.
Именно возможность вложение инструкций SQL друг в друга является причиной, по которой SQL получил свое название – Structured Query Language (структурированный язык запросов). Подзапросы могут иметь один из трех типов в зависимости от предложения WHERE внешнего запроса:
· подзапросы, которые не возвращают ни одного или возвращают несколько элементов и начинаются со слова IN или оператора сравнения и содержат ключевые слова ANY или ALL;
· подзапросы, которые возвращают единственное значение и начинаются с простого оператора сравнения;
· подзапросы, которые представляют собой проверку (тест) на существование и начинаются с ключевого слова EXISTS.
Рассмотрим примеры.
Чтобы узнать фамилии клиентов, которые останавливались в гостинице в феврале, можно выполнить следующий запрос:
SELECT Фамилия FROM Клиент
WHERE Код_клиента IN
(SELECT Код_клиента FROM Проживает
WHERE MONTH(П.Дата_прибытия) = 2
AND YEAR(П.Дата_прибытия) = 2006)
Рассмотрим, для чего нужны ключевые слова ANY и ALL. Если воспользоваться оператором сравнения >, то >ALL означает «больше, чем каждое значение». ANY означает «больше любого значения». Например, определим список клиентов, прибывших в гостиницу после Алексеева и Поповича.
SELECT К.Фамилия
FROM Проживает П, Клиент К
WHERE П.Код_клиента = К.Код_клиента
AND П.Дата_прибытия > ALL
(SELECT П1.Дата_прибытия
FROM Проживает П1, Клиент К1
WHERE П1.Код_клиента = К1.Код_клиента
AND К1.Фамилия IN ('Алексеев', 'Попович'))
Если внутренний подзапрос, стоящий после оператора сравнения и слова ALL, возвращает в качестве одного из значений NULL, то считается, что в целом запрос завершился неудачно.
Оператор ANY полностью эквивалентен оператору IN. Однако оператор <> ANY существенно отличается от оператора NOT IN. Например, следующие два запроса вернут разные результаты:
1. SELECT Код_клиента
FROM Клиент
WHERE Код_клиента NOT IN
(SELECT Код_клиента FROM Проживает
WHERE Дата_прибытия > '02/02/01')
Результат выборки:
Код_клиента
-----------
(3 row(s) affected)
2. SELECT Код_клиента
FROM Клиент
WHERE Код_клиента <> ANY
(SELECT Код_клиента FROM Проживает
WHERE Дата_прибытия > '02/02/01')
Второй запрос выводит коды всех клиентов. Это происходит потому, что оператор <>ANY трактуется как <>a ИЛИ <>b ИЛИ <>c, где a, b, c элементы списка, получаемые с помощью подзапроса.
Когда запрос начинается с ключевого слова EXISTS, он действует как «тест на существование». Другими словами, ключевое слово EXISTS в предложении WHERE выполняет проверку на существование (или отсутствие) данных, которые удовлетворяют критериям соответствующего подзапроса. Такие подзапросы имеют общую форму:
Начало инструкции SELECT, INSERT, UPDATE, DELETE или подзапроса
WHERE [NOT] EXISTS (подзапрос)
[Окончание инструкции SELECT, INSERT, UPDATE, DELETE или подзапроса]
Например, следующий запрос выводит список клиентов, проживавших в гостинице в 2006 году:
SELECT Фамилия
FROM Клиент
WHERE EXISTS
(SELECT * FROM Проживает
WHERE Код_клиента=Клиент.Код_клиента
AND YEAR(Дата_прибытия)=2006)
Синтаксис подзапросов, начинающихся с EXISTS, отличается от синтаксиса других подзапросов следующим:
· ключевому слову EXISTS не предшествует имя столбца, константа или какое-либо другое выражение;
· список выбора подзапроса практически всегда содержит только символ звездочки, поскольку выполняется лишь тест на существование строк, которые удовлетворяют условиям подзапроса.
Использование ключевых слов EXISTS и NOT EXISTS позволяет реализовать выполнение двух операций из теории множеств: поиск пересечения и разности. Пересечение двух множеств содержит все элементы, которые принадлежат обоим исходным множествам, а разность содержит элементы, принадлежащие только первому из двух множеств и не входящие во второе множество.