
Часть III. Операторы: exists, any, some, all
Продолжаем обсуждение подзапросов. Сегодня рассмотрим специальные операторы, которые используют подзапросы в качестве аргументов. До сих пор, мы говорили с Вами о том, что на выходе подзапрос должен возвращать одно единственное значение. Допускалось использование подзапросов, которые на выходе давали ряд значений, но тогда мы оговаривали условие использования оператора IN. Сегодня Вы познакомитесь с новыми операторами, которые позволяют решить вопросы связанные с получением на выходе от подзапроса нескольких строк.
Оператора EXISTS. Данный оператор, используя подзапрос в качестве аргумента, оценивает его как истинный, если подзапрос генерирует выходные данные или как ложный, если на выходе подзапрос не содержит данных. Таким образом, в результате применения EXISTS к подзапросу получаем TRUE или FALSE.
Одной из особенностей использования EXISTS, является то, что он не может принимать значение UNKNOWN. Вполне логично: если на выходе подзапрос, который является аргументом EXISTS, генерирует данные, то возвращается правда, в противном случае - ложь. Исходя из предыдущих размышлений, замечу, что оператор EXISTS позволяет нам работать с несколькими строками группы значений, в отличие от остальных операторов используемых с подзапросами. Вы, наверное, заметили что, часто в SQL одну и ту же задачу возможно решить несколькими способами. Рассмотрим следующий пример: "Выбрать всех студентов, которые когда-либо пользовались услугами библиотеки."
SELECT *
FROM Students s
WHERE EXISTS (
SELECT *
FROM S_Cards c
WHERE s.id=c.id_student
)
ORDER BY 2;
Обратите внимание, что в примере использовался связанный подзапрос. При применении связанных подзапросов оператор EXISTS применяется отдельно для каждой строки таблицы, на которую есть ссылка в основном запросе.
Следующие два оператора абсолютно идентичны и являются взаимозаменяемыми: это ANY и SOME. Как работают данные операторы? Продемонстрируем это на примере известного Вам запроса: "Выбрать всех студентов, которые когда-либо пользовались услугами библиотеки."
SELECT *
FROM Students
WHERE id= ANY (
SELECT id_student
FROM S_Cards
)
ORDER BY 2;
Оператор ANY берет все значения поля id_student в таблице S_Cards и оценивает результат как истину, если какое-либо значение совпадает со значением поля id из текущей строки внешнего запроса. Конечно, аналогичного результата возможно добиться и при использование оператора SOME.
SELECT *
FROM Students
WHERE id= SOME (
SELECT id_student
FROM S_Cards
)
ORDER BY 2;
Еще один специальный оператор, который мы сегодня рассмотрим, это оператор ALL. Данный оператор возвращает значение TRUE, если каждое значение, выбранное в процессе выполнения подзапроса, удовлетворяет условию, заданному в условии внешнего запроса. Рассмотрим следующий пример: "Выбрать всех авторов, написавших книги с объемом страниц большим, чем любая книга выпущенная издательством Питер".
SELECT Authors.FirstName & ' ' & Authors.LastNAme AS [Полное имя]
FROM Authors, Books
WHERE Authors.Id=Books.Id_Author
AND Books.Pages>ALL(
SELECT Books.Pages
FROM Books, Press
WHERE (Books.Id_press=Press.ID) AND (Press.NAME='Питер')
);
Если бы мы записали данный запрос без оператора ALL, тогда бы мы получили сообщение об ошибке: "Данный подчиненный запрос должен возвращать не более одной записи". Используя же оператор ALL мы добиваемся следующего желаемого эффекта: вначале выполняется подзапрос, который на выходе дает несколько результирующих строк. Затем значение каждой результирующей строки сравнивается с значением поля Pages таблицы Books. Если, в каждом из случаев, значение поля Pages таблицы BOOK будет больше соответсвующего значения каждой из результирующих строк, то результатом работы Books.Pages>ALL (...) будет TRUE. Дальнейшая обработка происходит по уже известным Вам правилам.
Объединения
Внутренние объединения
Операция объединения соединяет информацию из нескольких таблиц, отображая только связанные строки, то есть строки, которые имеют одинаковые значения в связанных столбцах разных таблиц. Мы уже писали множество таких запросов, например:
Select Faculties.Name, Groups.Name
From Faculties, Groups
Where Faculties.Id = Groups.Id_Faculty
Э тот запрос выводит информацию о факультетах и соответствующих им группах. И хотя подобный синтаксис используется повсеместно, в стандарте SQL2 запрос на внутреннее объединение выглядит несколько иначе:
Select Faculties.Name, Groups.Name
From Faculties Inner Join Groups
On Faculties.Id = Groups.Id_Faculty
Результат запроса представлен на рисунке
Отличие состоит в том, что связи между таблицами указываются с помощью инструкции INNER JOIN, а связи по ключевым полям (условия отбора) описываются после инструкции ON. Все остальные инструкции (Where, Group By, Having, Order By) могут использоваться далее по описанным в предыдущих уроках правилам.