Подзапросы
Запрос внутри запроса
Подзапрос — это SELECT, вложенный в другой запрос. Он удобен, когда для условия или столбца нужно сначала что-то вычислить другим запросом.
Скалярный подзапрос (одно значение)
Если подзапрос возвращает ровно одно значение, его можно сравнивать как обычное число. Классика — «дороже/быстрее среднего»:
SELECT airplane_code, model, speed
FROM airplanes
WHERE speed > (SELECT AVG(speed) FROM airplanes);
Сначала вычисляется внутренний SELECT AVG(speed) (одно число), затем внешний запрос сравнивает с ним каждую строку. Так же работают = (SELECT MAX(...)), < (SELECT AVG(...)) и т.п.
Подзапрос со списком: IN (...)
Если подзапрос возвращает столбец значений, его используют с оператором IN — «входит ли в этот список». Например, аэропорты, которые встречаются как аэропорт вылета хотя бы одного маршрута:
SELECT airport_code, city
FROM airports
WHERE airport_code IN (SELECT DISTINCT departure_airport FROM routes);
Есть и обратный оператор NOT IN — «не входит в список». Но у него есть ловушка: если подзапрос вернёт хотя бы один NULL, сравнение может стать неизвестным для всех строк и результат окажется пустым. Поэтому исключайте NULL внутри подзапроса или используйте коррелированный NOT EXISTS.
Подзапрос в списке SELECT
Скалярный подзапрос можно поставить и в список выбираемых столбцов — тогда у каждой строки появится одно и то же вычисленное значение (например, рекорд для сравнения):
SELECT model, speed, (SELECT MAX(speed) FROM airplanes) AS fastest
FROM airplanes;
Разбор: подзапрос выполняется «изнутри наружу»
В запросе SELECT model FROM airplanes WHERE speed > (SELECT AVG(speed) FROM airplanes) база сначала считает внутренний запрос — получается одно число, например 860. Затем внешний запрос выполняется так, будто вместо скобок написано это число: WHERE speed > 860.
Типичные ошибки
- Подзапрос вернул несколько строк. Со знаками
=,>,<подзапрос должен дать ровно одно значение, иначе будет ошибкаmore than one row returned by a subquery. Для списка значений используйтеIN. - NULL внутри NOT IN. Если подзапрос в
NOT IN (…)вернёт хотя бы одинNULL, результат будет пустым. Поэтому в подзапросе добавляютWHERE … IS NOT NULLили используютNOT EXISTS. - Подзапрос вместо JOIN. Если из второй таблицы нужно вывести столбцы, подзапрос в
WHEREне поможет — он только фильтрует. НуженJOIN.
💡 Запомните: для сравнения через=,>,<подзапрос должен возвращать одно значение; дляIN— столбец значений.
Практика
8- Тест 1 — Подзапрос в «WHERE speed = (SELECT speed FROM airplanes)» вернул несколько строк. Что будет?
- Тест 2 — Подзапрос внутри «NOT IN (…)» вернул среди значений NULL. Что получится?
- Задача 1 — Быстрее среднего
- Задача 2 — Самый дальнобойный (= MAX)
- Задача 3 — Аэропорты, используемые на вылет (IN)
- Задача 4 — Аэропорты без прилётов (NOT IN)
- Задача 5 — Бронирования дороже среднего
- Задача 6 — Маршруты самого быстрого самолёта
Задачи решаются прямо здесь, в браузере, на учебной базе — нужна только бесплатная регистрация, чтобы сохранялись ответы и прогресс.
Потренируйтесь в тренажёре
6Задачи на ту же тему, но на другой базе — продажи магазина электроники. Хороший способ проверить, что тема понятна, а не просто запомнилась на примерах урока.
- средняяУстройства дороже среднего
- средняяПродавцы выше среднего рейтинга
- средняяТоп-5 дорогих через ROWNUM (Oracle)
- сложнаяУстройства дороже среднего в своём типе
- сложнаяПродажи выше среднего чека продавца