SQLГлава 12. Использование оператора EXISTSТеперь, когда вы уже познакомились с подзапросами, мы можем поговорить о некоторых специальных операторах, которые всегда принимают подзапросы как аргументы. Вы узнаете о первом из их в этой главе. Остальные будут описаны в следующей главе.
Оператор Как работает EXISTS?
Это означает, что он может работать автономно в предикате или в комбинации с другими выражениями, использующими булевы операторы
Например, мы можем решить, извлекать ли нам некоторые данные из таблицы Заказчиков, если, и только если, один или более заказчиков в этой таблице находятся в SELECT cnum, cname, city FROM Customers WHERE EXISTS (SELECT * FROM Customers WHERE city = 'San Jose');
Внутренний запрос выбирает все данные для всех заказчиков в =============== SQL Execution Log ============ | | | SELECT snum, sname, city | | FROM Customers | | WHERE EXISTS | | (SELECT * | | FROM Customers | | WHERE city = 'San Jose'); | | ============================================= | | cnum cname city | | ----- -------- ---- | | 2001 Hoffman London | | 2002 Giovanni Rome | | 2003 Liu San Jose | | 2004 Grass Berlin | | 2006 Clemens London | | 2008 Cisneros San Jose | | 2007 Pereira Rome | =============================================== Рисунок 12.1 Использование оператора EXISTS Выбор столбцов с помощью EXISTS
В вышеупомянутом примере, Использование EXISTS с соотнесенными подзапросами
В соотнесённом подзапросе предложение SELECT DISTINCT snum FROM Customers outer WHERE EXISTS (SELECT * FROM Customers inner WHERE inner.snum = outer.snum AND inner.cnum < > outer.cnum); =============== SQL Execution Log ============ | | | SELECT DISTINCT cnum | | FROM Customers outer | | WHERE EXISTS | | (SELECT * | | FROM Customers inner | | WHERE inner.snum = outer.snum | | AND inner.cnum < > outer.cnum); | | ============================================= | | cnum | | ----- | | 1001 | | 1002 | =============================================== Рисунок 12.2 Использование EXISTS с соотнесённым подзапросом
Для каждой строки-кандидата внешнего запроса (представляющей заказчика, проверяемого в настоящее время) внутренний запрос находит строки, которые совпадают со значением поля Комбинация из EXISTS и объединенияОднако для нас может быть полезнее вывести больше информации об этих продавцах, а не только их номера. Мы можем сделать это, объединив таблицу Заказчиков с таблицей Продавцов (вывод для запроса показан на Рисунке 12.3): SELECT DISTINCT first.snum, sname, first.city FROM Salespeople first, Customers second WHERE EXISTS (SELECT * FROM Customers third WHERE second.snum = third.snum AND second.cnum < > third.cnum) AND first.snum = second.snum; =============== SQL Execution Log ============ | | | SELECT DISTINCT first.snum, sname, first.city | | FROM Salespeople first, Customers second | | WHERE EXISTS | | (SELECT * | | FROM Customers third | | WHERE second.snum = third.snum | | AND second.cnum < > third.cnum) | | AND first.snum = second.snum; | | ============================================= | | cnum cname city | | ----- -------- ---- | | 1001 Peel London | | 1002 Serres San Jose | =============================================== Рисунок 12.3 Комбинация EXISTS с объединением
Внутренний запрос здесь, как и в предыдущем варианте, фактически сообщает, что псевдоним был изменён. Внешний запрос это объединение таблицы Продавцов с таблицей Заказчиков, наподобие того, что мы видели прежде. Новое предложение основного предиката ( Использование NOT EXISTS
Предыдущий пример показал, что SELECT DISTINCT snum FROM Customers outer WHERE NOT EXISTS (SELECT * FROM Customers inner WHERE inner.snum = outer.snum AND inner.cnum < > outer.cnum); EXISTS и агрегаты
Одна вещь которую =============== SQL Execution Log ============ | | | SELECT DISTINCT snum | | FROM Salespeople outer | | WHERE NOT EXISTS | | (SELECT * | | FROM Customers inner | | WHERE inner.snum = outer.snum | | AND inner.cnum < > outer.cnum); | | ============================================= | | cnum | | ----- | | 1003 | | 1004 | | 1007 | =============================================== Рисунок 12.4 Использование EXISTS с NOT
Попытка использовать агрегаты с 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. =============== SQL Execution Log ============ | | | FROM Salespeople first | | WHERE EXISTS | | (SELECT * | | FROM Customers second | | WHERE first.snum = second.snum | | AND 1 < | | (SELECT CONT (*) | | FROM Orders | | WHERE Orders.cnum = second.cnum)); | | ============================================= | | cnum cname city comm | | ----- -------- ---- -------- | | 1001 Peel London 0.17 | | 1002 Serres San Jose 0.13 | | 1007 Rifkin Barselona 0.15 | =============================================== Рисунок 12.5 Использование EXISTS с комплексным подзапросом Мы могли бы разобрать вышеупомянутый запрос примерно так:
Берём каждую строку таблицы Продавцов как строку-кандидат (внешний запрос) и выполняем подзапросы. Для каждой строки-кандидата из внешнего запроса ставим в соответствие каждую строку из таблицы Заказчиков (средний запрос). Если текущая строка заказчиков не совпадает с текущей строкой продавца (т.е. если Если это не кажется достаточно понятным для вас на данной стадии разбора примера, не волнуйтесь. Сложность этого примера хороша, независимо от того, как часто вы будете использовать её в деловой ситуации. Основная цель примеров такого типа состоит в том, чтобы показать вам некоторые возможности, которые могут оказаться в дальнейшем полезными. После работы со сложными ситуациями, подобными этой, простые запросы, которые являются наиболее часто используемыми в SQL, покажутся вам элементарными. Кроме того, данный запрос, даже если он кажется удобным, довольно изощрён как способ извлечения информации и делает много работы. Он связывает три разные таблицы, чтобы дать вам эту информацию, а если таблиц больше, чем здесь указано, будет трудно получить её напрямую (хотя это не единственный способ, и не обязательно лучший способ в SQL). Возможно, вам нужно увидеть эту информацию относительно регулярной основы — если, например, вы имеете премию в конце недели для продавца, который получил несколько заказов от одного заказчика. В этом случае нужно было бы вывести команду и сохранить её, чтобы использовать снова и снова, по мере того как данные будут меняться (лучше всего сделать это с помощью представления, которое мы будем проходить в Главе 20). Резюме
Следующим шагом будет овладение тремя другими специальными операторами, которые принимают подзапросы как аргументы: это Работа с SQL
(См. ответы в Приложении A.) |
||