2.15. Операторы работы с подзапросами

Для работы с подзапросами есть несколько очень удобных операторов, которые мы еще не рассматривали. Первым оператором, с которым мы еще не работали, будет EXISTS. Этому оператору в качестве параметра передается запрос и если запрос возвращает хотя бы одну строку, то оператор возвращает истинное значение иначе ложь. В зависимости от этого, внешний запрос выносит решение, включать текущую запись в результирующий набор или нет.

Операторы ANY, SOME и ALL также позволяют расширить возможности подзапросов и работы с ними. Операторы ANY и SOME чем-то похожи на IN, с которым мы работали. Но чтобы увидеть все преимущества, необходимо посмотреть реальный запрос и разобрать его результат.

Теперь познакомимся поближе со всеми этими операторами и увидим их работу на практике.

2.15.1. EXISTS

По идее, оператор EXISTS нужно было рассмотреть намного раньше, потому что он достаточно прост. Но я решил повременить, потому что его удобно использовать совместно с подзапросами. Например, давайте выведем на экран всех работников, у которых есть хоть какой-либо телефон. Как это сделать? Можно связать две таблицы и те записи работников и получить связанные строки. Это и будут работники, у которых есть номера телефонов.

Но не всегда так легко решить проблему. Иногда удобнее и проще воспользоваться оператором EXISTS, который возвращает истинное значение, если запрос, который указан в скобках после оператора, возвращает хотя бы одну строку. Например:

SELECT * 
FROM tbPeoples pl
WHERE EXISTS (SELECT * 
  FROM tbPhoneNumbers pn 
  WHERE pl.idPeoples=pn.idPeoples)

В этом запросе мы запрашиваем все записи из таблицы tbPeoples, в качестве условия происходит проверка EXISTS. Для каждой записи работника выполняется запрос, который указан в скобках после EXISTS:

SELECT * 
FROM tbPhoneNumbers pn 
WHERE pl.idPeoples=pn.idPeoples 

Здесь мы связываем с внешним запросом таблицу tbPhoneNumbers. Если этот запрос найдет хотя бы один телефон для текущего работника, то EXISTS возвращает истину и строка попадает в результат.

Чтобы отобразить все записи работников, которые не имеют телефонов, достаточно перед EXISTS поставить оператор NOT:

SELECT * 
FROM tbPeoples pl
WHERE NOT EXISTS (SELECT * 
  FROM tbPhoneNumbers pn 
  WHERE pl.idPeoples=pn.idPeoples)

Благодаря оператору NOT происходит обратная операция, т.е. в результат попадает та строка, для которой запрос после EXISTS не вернул ни одной строки.

2.15.1. ANY, SOME и ALL

Операторы ANY и SOME абсолютно одинаковы. Оба они дают один и тот же результат, поэтому вы можете использовать тот, который больше нравиться. Мне больше нравиться ANY, потому что это слово короче аж на одну букву :).

В начале этой главы я намекнул на то, что ANY очень похож на IN. Давайте посмотрим на следующий запрос с оператором IN:

SELECT * 
FROM tbPhoneNumbers
WHERE idPhoneType IN
 (
  SELECT idPhoneType 
  FROM tbPhoneType 
  WHERE vcTypeName in ('Сотовый рабочий', 'Сотовый домашний')
 )

В данном примере используется IN для сравнения поля "idPhoneType" с одним из значений, возвращаемым подзапросом. То же самое можно сделать с помощью оператора ANY, только используется этот немного по-другому:

SELECT * 
FROM tbPhoneNumbers
WHERE idPhoneType > ANY
 (
  SELECT idPhoneType 
  FROM tbPhoneType 
  WHERE vcTypeName in ('Сотовый рабочий', 'Сотовый домашний')
 )

Так в чем же разница? А она кроется в том, как читается этот запрос. Попробуем проговорить его: «Выбрать все записи из таблицы tbPhoneNumbers, где поле "idPhoneType" равно любому из значений, полученных подзапросом». Разница в том, что IN работает также как и = ANY, но с оператором ANY можно использовать любые другие операторы сравнения: = или <> или != или > или >= или !> или < или <= или !<. Например, следующий запрос выбирает все телефоны из таблицы tbPhoneNumbers, у которых "idPhoneType" больше любого из значений, полученных в подзапросе:

SELECT * 
FROM tbPhoneNumbers
WHERE idPhoneType > ANY
 (
  SELECT idPhoneType 
  FROM tbPhoneType 
  WHERE vcTypeName in ('Сотовый рабочий', 'Сотовый домашний')
 )

Если ANY сравнивает с любым из значений и если "idPhoneType" будет больше хотя бы одного, то запись попадает в результат. Если ANY заменить на оператор ALL, то строка попадет в результирующий набор, только если она будет больше всех значений, которые возвращает подзапрос:

SELECT * 
FROM tbPhoneNumbers
WHERE idPhoneType > ALL
 (
  SELECT idPhoneType 
  FROM tbPhoneType 
  WHERE vcTypeName in ('Сотовый рабочий', 'Сотовый домашний')
 )

Если ANY и SOME требуют, чтобы условие выполнилось хотя бы с одной строкой результата подзапроса, то ALL будет требовать, чтобы условие выполнилось ко всем строкам.

Предыдущая глава

2.14. Подзапросы

Следующая глава

2.16. Добавление записей

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне