Глава 13. Исtrользование операторов ANY, ALL и SOME
FROM Customers
WHERE city = 'Boston');
полностью воспроизведет таблицу Customers. Поскольку в городе Bostoп нет никаких покупателей, все эти сравнения не имеют большого значения.
ANY и ALL вместо EXISTS с NULL-значениями
NULL-значения также создают некоторые проблемы для рассматриваемых опера торов. Когда SQL сравнивает два значения, одно из которых - NULL-значение, ре зультат принимает значение unknown (см. главу 5). Unknown-пpeдикaт, также как и fаlsе-предикат, создает ситуацию, когда строка не включается в состав выходных дан
ных, но результат различен для различных типов запросов, в зависимости от исполь
зования в них ALL или ANY вместо EXISTS. Рассмотрим приведенные ранее
примеры:
SELECT •
FROM Customers
WHERE rating > ANY
(SELECT rating
FROM Customers
WHERE city = 'Rome');
и:
SELECT •
FROM Customers outer
WHERE EXISTS
(SELECT •
FROM Customers inner
WHERE outer. rating > inner.rating
AND inner.city = 'Rome');
Оба эти запроса ведут себя совершенно одинаково. Предположим, что в таблице Customers есть строка с NULL-значением в столбце rating:
CNUM |
CNAME |
СIТУ |
RAТING |
SNUM |
2003 |
Liu |
San Jose |
NULL |
1002 |
В версии с ANY, когда выбирается поле rating для Mr. Liu в основном запросе, из за NULL-значения предикат принимает значение unknown, а строка с Liu не включает ся в состав выходных данных. Однако, когда версия NOT EXISTS выбирает эту строку в основном запросе, NULL-значение используется в предикате подзапроса, присваи вая ему всякий раз значение unknown. Это значит, что в результате выполнения подза-
140
Функционирование ANY, ALL и EXISTS при потере данных
проса не будет получено ни одного значения и EXISTS примет значение "ложь". Это, в свою очередь, сделает NOT EXISTS истинным. Следовательно, строка с Mr. Liu вклю
чается в состав выходных данных. Противоречие вытекает из того, что в отличие от
друrих типов предикатов, значение EXISTS - всегда "истина" или "ложь", а никогда
не unknown.
Это и является основанием для использования ANY. NULL-значение не превосхо дит любого реального значения. Более того, результат будет тот же, и необходимо ис
кать меньшее значение.
Использование COUNT вместо EXISTS
Было отмечено, что ANY и ALL могут быть (приближенно) заменены на EXISTS, тогда как обратное неверно. Верно и то, что подзапросы с EXISTS и NOT EXISTS мо гут быть заменены теми же самыми подзапросами с COUNT(*) в предложении подза проса SELECT. Если в состав выходных данных входит более чем О строк, то это
эквивалентно ситуации EXISTS; в противном случае это то же самое, что NOT EXISTS. Рассмотрим пример (выходные данные для запроса представлены на
рис. 13.12):
SELECT *
FROM Customers outer
WHERE NOT EXISTS
(SELECT *
FROM Customers inner
WHERE outer.rating <= inner.rating
AND inner.city = "Rome");
Его можно представить и так:
SELECT *
FROM Customers outer
WHERE 1 >
(SELECT COUNT(*)
FROM Customers inner
WHERE outer.rating <= inner.rating
AND inner.city = "Rome');
Выходные данные для этого запроса изображены на рис. 13.13.
141
Глава 13. Использование 011ераторов ANY, ALL и SOME
Рис. 13.12. Использование EXISTS со связанным подзапросом
Рис. 13.13. Использование COUNT вместо EXISTS
142
Итоги
Итоги
Эта глава содержит большой объем информации. Подзапросы - тема непростая, поэтому по мере изложения материала обсуждались и возможные варианты, и неодно значности. Вы узнали о разных методах работы с ошибками и NULL-значениями. У вас есть теперь несколько способов решения проблемы и возможность выбора опти
мального варианта.
После разбора наиболее важного и сложного аспекта SQL, оставшийся материал сравнительно прост для понимания. Следующая глава тоже посвящена запросам. Вы научитесь комбинировать выходные данные для любого количества запросов в един ственном теле с целью формирования объединения множества запросов с использова нием предложения UNION.
143
Работаем на SQL
l.Запишите запрос, выбирающий всех покупателей, рейтинг которых равен или превосходит ANY (в смысле SQL) Serres.
2.Какие выходные данные генерирует эта команда?
3.Запишите запрос, использующий ANY или ALL, который будет находить всех
продавцов, не имеющих покупателей в их городе.
4.Запишите запрос, выбирающий всех покупателей, значение поля amount кото рых превышаетлюбое значение (в обычном смысле) для покупателей Лондона.
5.Запишите этот же запрос с использованием МАХ.
(Ответы см. в приложении А.)
144