Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
БД.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
44.43 Кб
Скачать

17. Подзапрос, виды подзапросов (определение, перечислить с указанием допустимых операторов для объединения с главным запросом, перечисть разделы оператора select, где могут использоваться).

Вложенный подзапрос – это оператор SELECT, заключенный в круглые скобки и вложенный в команду языка DML, и использующийся в качестве источника данных для параметров SELECT, FROM, WHERE и HAVING. Каждый подзапрос в свою очередь может содержать в себе подзапрос и т.д. В каждой СУБД существуют ограничения на количество вложенных подзапросов, но обычно этих ограничений хватает, чтобы реализовать задачи любой известной сложности.

Например, чтобы определить, уровень продаж каких товаров превышает средний уровень, необходимо предварительно вычислить этот средний уровень.

Все подзапросы можно условно разделить на однострочные и многострочные, а также на простые и коррелированные.

Однострочные подзапросы возвращают в качестве результата всегда одну строку, не больше и не меньше, поэтому над результатами выполнения таких запросов можно использовать операции сравнения.

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

Простыми, или независимыми, подзапросами называются вложенные подзапросы, выполнение которых не зависит от внешнего запроса. Простые вложенные подзапросы обрабатываются системой «снизу вверх». Первым обрабатывается вложенный подзапрос самого нижнего уровня. Множество значений, полученное в результате его выполнения, используется при реализации подзапроса более высокого уровня и т.д.

Запросы с коррелированными вложенными подзапросами обрабатываются системой в обратном порядке. Сначала выбирается первая строка рабочей таблицы, сформированной основным запросом, и из нее выбираются значения тех столбцов, которые используются во вложенном подзапросе (вложенных подзапросах). Если эти значения удовлетворяют условиям вложенного подзапроса, то выбранная строка включается в результат. Затем выбирается вторая строка и т.д., пока в результат не будут включены все строки, удовлетворяющие вложенному подзапросу (последовательности вложенных подзапросов).

Однострочные вложенные подзапросы

Однострочные вложенные подзапросы чаще всего применяются совместно с агрегатными функциями, результат вычисления которых и является единственным результатом подзапроса. Например: 

-- получить имя менеджера, имеющего максимальное

-- значение размера комиссионных

SELECT Name FROM Managers WHERE Procent =

(SELECT Max(Procent) FROM Managers);

 В данном случае вложенный подзапрос должен выполняться для каждой строки, обрабатываемой во внешнем запросе. Но очевидно, что результат вложенного запроса никоим образом не зависит от того, какая строка обрабатывается во внешнем запросе. В таких случаях, чтобы не выполнять один и тот же вложенный подзапрос, независящий от внешнего запроса, некоторые СУБД кэшируют (запоминают) результат, полученный в результате первого выполнения вложенного подзапроса, и подставляют для всех остальных строк таблиц, обрабатываемых во внешнем запросе.

 -- получить имя менеджера, осуществившего

-- максимальное количество сделок продажи

SELECT Name FROM Managers

WHERE Man_id=

(SELECT Man_id FROM Outgoing

WHERE ROWNUM=1

GROUP BY Man_id

HAVING COUNT(Out_id)=

(SELECT MAX(COUNT(Out_id)) FROM Outgoing

GROUP BY Man_id)); 

В данном запросе в параметре WHERE указано условие ROWNUM=1, благодаря которому соблюдается условие выбора единственного значения во вложенном подзапросе, иначе вложенный подзапрос может вернуть более одной строки (если несколько менеджеров осуществили максимальное количество сделок), тогда результат выполнения подзапроса нельзя будет использовать в операциях сравнения. О способах применения столбца ROWNUM для частичного вывода запрошенных данных смотри далее раздел «Частичный вывод запрошенных данных».

Если необходимо вывести имена всех менеджеров, осуществивших одинаковое максимальное количество сделок продажи, можно выполнить следующий запрос: 

SELECT m.Name FROM Managers m, Outgoing o

WHERE m.Man_id=o.Man_id

GROUP BY m.Name

HAVING COUNT(o.Out_id)=

(SELECT MAX(COUNT(Out_id)) FROM Outgoing

GROUP BY Man_id); 

Многострочные вложенные подзапросы

Многострочные вложенные подзапросы используются для представления множества значений, исследование которых должно осуществляться в каком-либо предикате IN, что иллюстрируется в следующем примере: 

-- определение имен менеджеров, которые не осуществили

-- ни одной сделки продажи

SELECT Name FROM Managers WHERE Man_Id NOT IN

(SELECT DISTINCT Man_Id FROM Outgoing); 

Иногда с использованием многострочных подзапросов также можно решать задачи, которые обычно решаются простым соединением таблиц внутри одного запроса, например: 

-- вывод имен менеджеров, осуществивших

-- хотя бы одну сделку продажи

SELECT Name FROM Managers WHERE Man_Id IN

(SELECT DISTINCT Man_Id FROM Outgoing); 

-- аналогичная задача решается путем простого соединения

-- таблиц Managers и Outgoing

SELECT Name FROM Managers, Outgoing

WHERE Managers.Man_id=Outgoing.Man_id; 

Коррелированные вложенные подзапросы

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

-- вывести имена менеджеров и даты сделок, в которых они

-- продали максимальное для себя количество товаров

SELECT Name, Out_Date FROM Managers m, Outgoing o

WHERE m.Man_id=o.Man_id AND o.Quantity=

(SELECT MAX(Quantity) FROM Outgoing

WHERE Man_id=m.Man_id); 

C концептуальной точки зрения обработка всего запроса в целом осуществляется следующим образом:

Система проверяет первую строку таблицы MANAGERS. Предположим, что это строка менеджера с номером 1. Тогда значение поля m.Man_id будет в данный момент иметь значение, равное 1, и система обрабатывает внутренний запрос: 

(SELECT MAX(Quantity) FROM Outgoing

WHERE Man_id=1); 

получая в результате одно число, равное максимальному количеству товара проданного менеджером с номером 1. Теперь система может завершить обработку для менеджера с номером 1, просто выбрав из таблицы Outgoing дату сделки, в которой менеджером с номером 1 было продано вычисленное в подзапросе количество товара.

Далее система будет повторять обработку такого рода для следующего менеджера и т.д. до тех пор, пока не будут рассмотрены все строки таблицы Managers.

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

Запросы с использованием EXISTS

Квантор EXISTS (существует) – понятие, заимствованное из формальной логики. В языке SQL предикат с квантором существования представляется выражением EXISTS (SELECT * FROM ...).

Такое выражение считается истинным только тогда, когда результат вычисления «SELECT * FROM ...» является непустым множеством, т.е. когда существует какая-либо запись в таблице, указанной во фразе FROM подзапроса, которая удовлетворяет условию WHERE подзапроса (практически этот подзапрос всегда будет коррелированным множеством). Например: 

-- выдать наименования продуктов,

-- проданных менеджером с номером 1

SELECT Name FROM Products p

WHERE EXISTS

(SELECT Prod_id FROM Outgoing

WHERE Prod_id=p.Prod_id AND Man_id = 1);

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]