EXISTS И АГРЕГАТЫ
Одна вещь которую EXISTS не может сделать - взять функцию агрегата в
подзапросе. Это имеет значение. Если функция агрегата находит любые строки для операций с ними, EXISTS
верен, не
взирая на то, что это - значение функции ; если же агрегатная функция не находит никаких строк, EXISTS
неправилен.
Рисунок 12.4: Использование EXISTS с NOT
Попытка
использовать агрегаты с EXISTS таким способом, вероятно покажет что проблема неверно решалась от начала
до конца.
Конечно, подзапрос в предикате EXISTS может также использовать один или более из его собственных подзапросов.
Они
могут иметь любой из различных типов которые мы видели ( или который мы будем видеть ). Такие
подзапросы, и любые
другие в них, позволяют использовать агрегаты, если нет другой причины по которой они не могут быть
использованы.
Следующий раздел приводит этому пример. В любом случае, вы можете получить тот же самый результат более
легко,
выбрав поле которое вы использовали в агрегатной функции, вместо использования самой этой функции. Другими
словами,
предикат - EXISTS (SELECT COUNT (DISTINCT sname) FROM Salespeople) - будет эквивалентен - EXISTS (SELECT sname
FROM Salespeople) который был позволен выше.
БОЛЕЕ УДАЧНЫЙ ПРИМЕР ПОДЗАПРОСА
Возможные прикладные
программы подзапросов могут становиться многократно вкладываемыми. Вы можете вкладывать их два или более
в
одиночный запрос, и даже один внутрь другого. Так как можно рассмотреть небольшой кусок чтобы получить
всю картину
работаты этой команды, вы можете воспользоваться способом в SQL, который может принимать различные команды
из
большинства других языков. Имеется запрос который извлекает строки всех продавцов которые имеют заказчиков
с больше
чем одним текущим порядком. Это не обязательно самое простое решение этой проблемы, но оно предназначено
скорее
показать улучшеную логику SQL. Вывод этой информации связывает все три наши типовых таблицы:
SELECT * FROM
Salespeople first WHERE EXISTS ( SELECT * FROM Customers second WHERE first.snum = second.snum AND 1 < ( SELECT
COUNT (*) FROM Orders WHERE Orders.cnum = second.cnum ));
Вывод для этого запроса показывается в Рисунке 12.5.
cnum |
cname |
city |
comm |
1001 |
Peel |
London |
0.17 |
1002 |
Serres |
San Jose |
0.13 |
1007 |
Rifkin |
Barselona |
0.15 |
Рисунок 12.5: Использование EXISTS с комплексным подзапросом
Мы могли бы разобрать вышеупомянутый запрос примерно так: Берем каждую строку таблицы Продавцов как
строку-кандидат( внешний запрос ) и выполняем подзапросы. Для каждой строки-кандидата из внешнего запроса,
берем в
соответствие каждую строку из таблицы Заказчиков( средний запрос ). Если текущая строка заказчиков не
совпадает с
текущей строкой продавца( т.е. если first.snum < > second.snum ), предикат среднего запроса неправилен.
Всякий раз, когда мы
находим заказчика в среднем запросе который совдает с продавцом во внешнем запросе, мы должны рассматривать
сам
внутренний запрос чтобы определить, будет ли наш средний предикат запроса верен. Внутренний запрос
считает число
порядков текущего заказчика ( из среднего запроса ). Если это число больший чем 1, предикат среднего
запроса верен, и
строки выбираются. Это делает EXISTS предикат внешнего запроса верным для текущей строки продавца, и
означает, что по
крайней мере один из текущих заказчиков продавца имеет более чем один порядок. Если это не кажется
достаточно
понятным для вас в этой точке разбора примера, не волнуйтесь. Сложность этого примера - хороша независимо
от того, как
часто будете Вы использовать ее в деловой ситуации. Основная цель примеров такого типа состоит в том,
чтобы показать
вам некоторые возможности которые могут оказаться в дальнейшем полезными. После работы со сложными
ситуациями
подобно этой, простые запросы которые являются наиболее часто используемыми в SQL, покажутся Вам элементарными.
Кроме того, этот запрос, даже если он кажется удобным, довольно извилистый способ извлечения информации
и делает
много работы. Он связывает три разных таблицы чтобы дать вам эту информацию, а если таблиц больше чем
здесь указано,
будет трудно получить ее напрямую (хотя это не единственный способ, и не обязательно лучший способ в
SQL). Возможно
вам нужно увидеть эту информацию относительно регулярной основы - если, например, вы имеете премию в
конце недели
для продавца который получил многочисленые порядки от одного заказчика. В этом случае, он должен был
бы вывести
команду, и сохранять ее чтобы использовать снова и снова по мере того как данные будут меняться ( лучше всего сделать это
с помощью представления, которое мы будем проходить в познее ).