2.8.     Вложенные подзапросы

SQL позволяет использовать одни запросы внутри других за­просов, то есть вкладывать запросы друг в друга. Предположим, известна фамилия студента («Петров»), но неизвестно значение поля STUDENT_ID для него. Чтобы извлечь данные обо всех оценках этого студента, можно записать следующий запрос:

SELECT *

FROM EXAM_MARKS WHERE STUDENT_ID =

(SELECT STUDENT_ID FROM STUDENT SURNAME =   'Щорсе11;

Как работает запрос SQL со связанным подзапросом?

* Выбирается строка из таблицы, имя которой указано во внешнем запросе.

* Выполняется подзапрос и полученное значение применяется для анализа этой строки в условии предложения WHERE внешнего запроса.

* По результату оценки этого условия принимается решение о включении или не включении строки в состав выходных данных.

• Процедура повторяется для следующей строки таблицы внешнего запроса.

Следует обратить внимание, что приведенный выше за­прос корректен только в том случае, если в результате выпол­нения указанного в скобках подзапроса возвращается единст венное значение. Если в результате выполнения подзапроса бу­дет возвращено несколько значений, то этот подзапрос будет ошибочным. В данном примере это произойдет, если в табли­це STUDENT будет несколько записей со значениями поля

SURNAME = 'Петров'.

В некоторых случаях для гарантии получения единственно­го значения в результате выполнения подзапроса используется DISTINCT. Одним из видов функций, которые автоматически всегда выдают в результате единственное значение для любого количества строк, являются агрегирующие функции.

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

Данные обо всех оценках (таблица EXAM MARKS) студентов из Воронежа можно выбрать с помощью следующего запроса:

SELECT *

FROM EXAM_MARKS WHERE STUDENT_ID IN

(SELECT STUDENT_I D PROM STUDENT WHERE CITY = 'B=pcf»K');

Подзапросы можно применять внутри предложения HAVING. Пусть требуется определить количество предметов обучения с оценкой, превышающей среднее значение оценки студента с идентификатором 301:

SELECT СОЭНГ (DISTINCT SUBJ_IDj , MARK FROM EXAM_MARKS GROUP BY MARK HAVING   MARK >

 (SELECT AVG (MARK) FROM EXAM_MARKS WHERE STUDENT_ID = 301);