Понимание SQL
Шрифт:
FROM Customers
WHERE city=" San Jose' );
Вы могли бы также использовать оператор ANY:
SELECT *
FROM Customers
WHERE NOT rating=ANY
( SELECT rating
FROM Customers
WHERE city=" San Jose' );
Вывод будет одинаков для всех трех условий.
ПРАВИЛЬНОЕ ПОНИМАНИЕ ANY И ALL
В SQL, сказать что - значение больше( или меньше ) чем любое(ANY) из набора значений - тоже самое что сказать, что оно больше( или меньше ) чем любое одно отдельное из этих значений. И наоборот, сказать что значение не равно всему(ALL) набору значений, тоже что сказать,
КАК ANY, ALL, И EXIST ПОСТУПАЮТM С ОТСУТСТВУЮЩИМИ И НЕИЗВЕСТНЫМИ ДАННЫМИ
Как было сказано, имеются некоторые различия между EXISTS и операторами представленными в этой главе относительно того как они обрабатывают оператор NULL. ANY и ALL также отличаются друг от друга тем как они реагируют если подзапрос не произвел никаких значений чтобы использовать их в сравнении. Эти различия могут привести к непредвиденным результатам на Ваши запросы если вы не будете их учитывать.
Одно значительное различие между ALL и ANY - способ действия в cитуации когда подзапрос не возвращает никаких значений. В принципе, всякий раз, когда допустимый подзапрос не в состоянии сделать вывод, ALL - автоматически верен, а ANY автоматически неправилен. Это означает, что следующий запрос
SELECT *
FROM Customers
WHERE rating > ANY
( SELECT rating
FROM Customers
WHERE city=Boston );
не произведет никакого вывода, в то время как запрос -
SELECT
FROM Customers
WHERE rating > ALL
( SELECT rating
FROM Customers
WHERE city='Boston' );
выведет всю таблицу Заказчиков. Когда нет никаких заказчиков в Boston,
естественно, ни одно из этих сравнений не имеет значення.
ANY И ALL ВМЕСТО EXISTS С ПУСТЫМ УКАЗАТЕЛЕМ( NULL )
Значения NULL также имеют некоторые проблемы с операторами наподобие этих. Когда SQL сравнивает два значения в предикате, одно из которых пустое (NULL), то результат неизвестен (смотрите Главу 5). Неизвестный предикат, подобен неверному и является причиной того что строка не выбирается, но работать он будет иначе в некоторых похожих запросах, в зависимости от того, используют они 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' );
В общем, эти два запроса будут вести себя одинаково. Но предположим, что появилось пустое(NULL) значение в столбце rating таблицы Заказчиков:
CNUM CNAME CITY RATING SNUM 2003 Liu SanJose NULL 1002
В варианте с ANY, где оценка Liu выбрана основным запросом, значение NULL делает предикат неизвестным а строка Liu не выбирается для вывода. Однако, в варианте с NOT EXISTS когда эта строка выбрана основным запросом, значение NULL используется в предикате подзапроса, делая его неизвестным в каждом случае. Это означает что подзапрос не будет производить никаких значений, и EXISTS будет неправилен. Это, естественно, делает оператор NOT EXISTS верным. Следовательно, строка Liu будет выбрана для вывода. Это основное расхождение, в отличие от других типов предикатов, где значение EXISTS независимо от того верно оно или нет - всегда неизвестно. Все это является аргументом в пользу использования варианта формулировки с 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 NOT EXISTS (SELECT * FROM Customers inner
WHERE outer.rating <=inner.rating AND inner.city='Rome');
cnum | cname | city | rating | snum |
2004 | Grass | Berlin | 300 | 1002 |
2008 | Cisneros | San Jose | 300 | 1007 |
Таблица 13.12: Использование EXISTS с соотнесенным подзапросом
Это должно также быть выполнено как
SELECT *
FROM Customers outer
WHERE 1 >
( SELECT COUNT (*)
FROM Customers inner
WHERE outer.rating <=inner.rating
AND inner.city='Rome' );
Вывод к этому запросу показывается в Таблице 13.13.
Теперь Вы начинаете понимать сколько способов имеется в SQL. Если это все кажется несколько путанным на этой стадии, нет причины волноваться. Вы обучаетесь чтобы использовать ту технику которая лучше всего отвечает вашим требованиям и наиболее понятна для вас. Начиная с этого места, мы хотим показать Вам большое количество возможностей, что бы вы могли найти ваш собственный стиль.
SELECT * FROM Customers outer
WHERE 1 > (SELECT COUNT (*) FROM Customers inner
WHERE outer.rating <=inner.rating
AND inner.city='Rome');
cnum | cname | city | rating | snum |
2004 | Grass | Berlin | 300 | 1002 |
2008 | Cisneros | San Jose | 300 | 1007 |