УРОК 16 / 27· ≈ 30 мин

Подзапросы

Запрос внутри запроса

Подзапрос — это 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. Тест 1 — Подзапрос в «WHERE speed = (SELECT speed FROM airplanes)» вернул несколько строк. Что будет?
  2. Тест 2 — Подзапрос внутри «NOT IN (…)» вернул среди значений NULL. Что получится?
  3. Задача 1 — Быстрее среднего
  4. Задача 2 — Самый дальнобойный (= MAX)
  5. Задача 3 — Аэропорты, используемые на вылет (IN)
  6. Задача 4 — Аэропорты без прилётов (NOT IN)
  7. Задача 5 — Бронирования дороже среднего
  8. Задача 6 — Маршруты самого быстрого самолёта

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

Зарегистрироваться и решитьВойти

Потренируйтесь в тренажёре

6

Задачи на ту же тему, но на другой базе — продажи магазина электроники. Хороший способ проверить, что тема понятна, а не просто запомнилась на примерах урока.

Все задачи тренажёра →
Внешние соединения и JOIN с группировкойСледующий урок: Общие табличные выражения (WITH / CTE)