В языке SQL есть возможность вкладывать запрос внутрь другого запроса. Такие запросы называются вложенными запросами или подзапросами. Существует три разновидности вложенных запросов:
- Вложенный запрос, возвращающий одно значение;
- Вложенный запрос, возвращающий несколько значений;
- Соотнесенный (коррелирующий) подзапрос.
Вложенный запрос, возвращающий одно значение
В этом случае вложенный запрос размещается в инструкции WHERE основного запроса, как показано на рисунке:
При этом следует помнить, что вложенный запрос должен возвращать гарантированно одно значение. Именно с этим значением будет производиться сравнение. Если вложенный запрос вернет несколько значений, то сравнение произвести не удастся из-за отсутствия однозначности.
Пусть в таблице spec хранится список специальностей вуза. Каждая специальность прикреплена к своему факультету. Факультеты хранятся в таблице facult. Таким образом, имеется связь типа «один-ко-многим» между факультетами и специальностями.
Необходимо получить список специальностей факультета «математический».
С этой целью выполним запрос:
SELECT spec.namespec FROM spec WHERE spec.idfacult=(SELECT facult.idfacult FROM facult WHERE facult.namefacult="математический");
- Сначала выполнится вложенный запрос SELECT facult.idfacult FROM facult WHERE facult.namefacult="математический"; Он вернет одно числовое значение 1 – уникальный код математического факультета.
- Потом полученное значение будет подставлено в основной запрос:
SELECT spec.namespec FROM spec WHERE spec.idfacult=1;
В итоге будет получен список из двух специальностей: Прикладная математика и Кибернетика.
Вложенный запрос, возвращающий список значений
Если вложенный запрос может вернуть список значений, то синтаксис должен быть немного другим:
Здесь вместо знака равно в инструкции WHERE используется оператор IN, который будет сравнивать значение поля со списком значений.
Попробуем вывести список заявлений, поданных на математический факультет. Задача отличается от предыдущей тем, что на факультете несколько специальностей. Следовательно, нужно искать заявления, которые поданы не на одну специальность, а на целый список специальностей:
SELECT * FROM application WHERE application.idspec IN (select spec.idspec from spec where spec.idfacult=1);
- Вложенный запрос вернет нам список с кодами двух специальностей, которые находятся на факультете. Это будут специальности с кодами 1 и 6.
- После этого выполнится внешний запрос:
SELECT * FROM application WHERE application.idspec IN (1,6);
Он вернет список заявлений, поданных на специальности 1 и 6.
Соотнесенные (коррелирующие) подзапросы
Соотнесенный(коррелирующий) подзапрос – это подзапрос, который содержит ссылку на поля из внешнего запроса.
Пусть каждый абитуриент подал несколько заявлений на разные специальности. У заявления есть много атрибутов: форма обучения, приоритет, курс, специальность и т.д. Для каждого абитуриента нужно заявление, которое было подано им последним. (Допустим, абитуриент Василий Тапкин подал три заявления. Из этого списка необходимо только то заявление, которое было подано позже двух других.)
Найти такие заявления очень просто запросом с группировкой по коду абитуриента:
SELECT max(idapplication) FROM application group by idabiturient;
Но в результате мы получим только код заявления, в то время как нужно видеть все атрибуты заявления - форму, специальность, приоритет, курс и т.д. Добавлять «лишние» поля в групповые запросы крайне нежелательно. Поэтому задачу лучше всего решать с помощью соотнесенного подзапорса.
SELECT * FROM application outquery WHERE outquery.idapplication = (SELECT max(idapplication) FROM application innerquery where outquery.idabiturient=innerquery.idabiturient);
outquery и innerquery здесь являются псевдонимами для внешней и внутренней части.
- Сначала внешним запросом выбирается очередная запись. Для этой записи определяется значение поля idabiturient. Это и будет outquery.idabiturient.
- Потом выполняется внутренний подзапрос с подстановкой, полученного на первом шаге, значения outquery.idabiturient. В результате получается максимальный номер заявления для данного абитуриента.
- Во внешнем запросе выбирается запись с полученным на втором шаге максимальным номером заявления.