Подзапросы и структурированные запросы

 

Подзапрос – дополнительный метод манипулирования несколькими таблицами. Другими словами, это инструкция 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 позволяет реализовать выполнение двух операций из теории множеств: поиск пересечения и разности. Пересечение двух множеств содержит все элементы, которые принадлежат обоим исходным множествам, а разность содержит элементы, принадлежащие только первому из двух множеств и не входящие во второе множество.