Вложенный подзапрос – это запрос, результат выполнения которого предается в качестве аргумента в другой запрос. Способом вкладывания подзапроса в запрос является его использование во фразе WHERE или HAVING в правом аргументе одного из следующих предикатов: IN, EXISTS =, <>, <,| <=,| >,| >=.
Существуют простые (независимые) и коррелированные (зависимые) вложенные подзапросы.
Простой (независимый) вложенный подзапрос – это такой подзапрос, вычисление которого происходит независимо от вычисления внешнего запроса. Такие запросы обрабатываются системой "снизу вверх". Первым обрабатывается вложенный подзапрос. Множество значений, полученное в результате его выполнения, используется при реализации внешнего подзапроса.
Коррелированный (зависимый, связанный) вложенный подзапрос – это такой подзапрос, вычисление которого зависит от процесса вычисления во внешнем запросе. Такие запросы обрабатываются системой в обратном порядке. Сначала выбирается текущая строка из таблицы внешнего запроса и на основании значений ее полей производится вычисление подзапроса (то есть в условии вычисления подзапроса присутствуют значения полей из внешнего запроса). Затем проверяется условие WHERE на включение текущей строки внешнего запроса в результат.
Возврат одного значения. При использовании предикатов, сравнивающих два значения ( =, ¹, <, £, >, ³), подзапрос должен возвращать одно значение. В противном случае выдается сообщение об ошибке.
1) Выдать список кафедр ВУЗа, которые располагаются в том же корпусе, что и кафедра вычислительной техники.
SELECT Name
FROM DEPARTMENT
WHERE Building = (SELECT Building
FROM DEPARTMENT
WHERE Name = 'CS')
Внутренний запрос определяет корпус кафедры 'CS'; он используется в предикате сравнения (=) внешнего запроса.
В подзапросе можно использовать агрегатную функцию, гарантирующую возвращение единственного значения.
2) Выдать факультеты, фонд которых превышает фонд всех кафедр факультета информатики.
SELECT Name
FROM FACULTY
WHERE Fund > (SELECT SUM(DEPARTMENT.Fund)
FROM FACULTY, DEPARTMENT
WHERE FACULTY.#F = DEPARTMENT.#F AND FACULTY.Name = 'IT'
Возврат многих значений. Если используется предикат, проверяющий вхождение ( IN ) или не вхождение ( NOT IN ) отдельного значения во множество (или некоторые другие, о которых пойдет речь далее), то подзапрос может возвращать множество значений.
3) Кто из преподавателей факультета информатики также работает на других факультетах.
SELECT TEACHER.Name
FROM FACULTY, DEPARTMENT, TEACHER
WHERE FACULTY.#F = DEPARTMENT.#F AND
DEPARTMENT.#D = TEACHER.#D AND
FACULTY.Name = 'IT' AND
TEACHER.Name IN
(SELECT TEACHER.Name
FROM FACULTY, DEPARTMENT, TEACHER
WHERE FACULTY.#F = DEPARTMENT.#F AND
DEPARTMENT.#D = TEACHER.#D AND
FACULTY.Name != 'IT')
Коррелирование (связывание) подзапроса с запросом. В некоторых случаях характер вычисления подзапроса зависит от значения текущей строки внешнего запроса. Это хорошо демонстрируется следующим примером. Обратите внимание, что в подзапросе во фразе FROM присутствует только отношение DEPARTMENT, однако во фразе WHERE мы ссылаемся к отношению FACULTY. Это означает, что происходит обращение к внешнему запросу. При наличии такого обращения процедура вычисления следующая: фиксируется текущая строка внешнего отношения, затем для вычисления условия фразы WHERE производится вычисление подзапроса. При этом используются значения столбцов текущей строки внешнего запроса.
Обработка коррелированного подзапроса, следовательно, должна повторяться для каждого значения извлекаемого из внешнего подзапроса, а не выполняться раз и навсегда как в не связанном подзапросе. Рассмотрим несколько примеров такого связывания.
1) Выдать факультеты, у которых фонд финансирования меньше, чем сумма фондов финансирования всех их кафедр:
SELECT Name
FROM FACULTY
WHERE Fund < (SELECT SUM(Fund)
FROM DEPARTMENT
WHERE DEPARTMENT.#F = FACULTY.#F )
2) Выдать преподавателей, не являющиеся кураторами групп
SELECT Name
FROM TEACHER
WHERE NOT EXISTS (SELECT *
FROM GROUP
WHERE TEACHER.#T = GROUP.#Curator )
(О предикате EXISTS см. далее).
Подзапрос во фразе HAVING. Как уже отмечалось, подзапросы могут вкладываться и во фразе HAVING.
4) Выдать названия кафедр и количество студентов на них для тех кафедр, количество студентов на которых больше, чем на кафедре инженерии программного обеспечения (SE).
SELECT DEPARTMENT.Name, SUM(GROUP.Quantity)
FROM DEPARTMENT, GROUP
WHERE DEPARTMENT.#D = GROUP.#D
GROUP BY DEPARTMENT
HAVING SUM(GROUP.Quantity) > (SELECT SUM(GROUP.Quantity)