← К оглавлению занятия

Занятие 25. Подзапросы

📁 Блок: SQL / MySQL / Подзапросы и CTE ⏱️ Время изучения: ~90 мин 🎯 Сложность: Средняя
#in #where #select #from

⚡ Кратко: суть темы

Подзапрос — это SELECT внутри другого запроса. Используется в WHERE (фильтр) и FROM (временная таблица). Всегда в скобках.

  • Скалярный — одно значение; с ним работают =, >, <.
  • Многострочный — список значений; с ним работают IN, ANY, ALL.

📖 Что такое подзапрос

Подзапрос (subquery) — это SQL-запрос, вложенный внутрь другого SQL-запроса. Внешний запрос использует результат подзапроса так же, как значение, таблицу или набор строк.

SELECT * FROM orders
WHERE customer_id IN (
    SELECT id FROM customers WHERE city = 'Los Angeles'
);
  • Внешний запрос: SELECT * FROM orders ...
  • Подзапрос: (SELECT id FROM customers WHERE city = 'Los Angeles')

Подзапрос всегда заключается в круглые скобки.

📖 Подзапрос в WHERE

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

SELECT * FROM orders
WHERE customer_id IN (
    SELECT id FROM customers WHERE city = 'Los Angeles'
);

Сначала внутренний запрос находит идентификаторы клиентов из Лос-Анджелеса, затем внешний запрос выбирает их заказы.

📖 Подзапрос в FROM

Подзапрос в FROM создаёт временный набор данных, который используется как таблица. Обычно применяется для предварительной агрегации.

SELECT p.product_name, ps.total_orders, ps.total_revenue
FROM (
    SELECT product_id,
           COUNT(*) AS total_orders,
           SUM(unit_price * quantity) AS total_revenue
    FROM order_details
    GROUP BY product_id
) AS ps
JOIN products AS p ON ps.product_id = p.id
ORDER BY ps.total_orders DESC
LIMIT 10;

Подзапрос агрегирует данные по продуктам; внешний запрос соединяет результат с products, чтобы получить названия.

📖 Скалярный подзапрос

Скалярный подзапрос возвращает ровно одно значение (одну строку и один столбец). Его можно использовать с операторами сравнения: =, <>, >, <, >=, <=.

SELECT *
FROM order_details
WHERE unit_price > (
    SELECT AVG(unit_price) FROM order_details
);

Если скалярный подзапрос вернёт более одной строки, СУБД выдаст ошибку.

📖 Многострочный подзапрос

Многострочный подзапрос возвращает столбец с несколькими значениями. С ним используются операторы IN, ANY, ALL, EXISTS.

SELECT *
FROM orders
WHERE employee_id IN (
    SELECT id FROM employees WHERE job_title = 'Sales Representative'
);

📖 Преимущества и недостатки

Преимущества

  • Позволяют разбить сложную задачу на простые шаги.
  • Часто читаемее сложных JOIN и UNION.
  • Изолируют промежуточную логику.

Недостатки

  • Могут работать медленнее эквивалентных JOIN.
  • Глубоко вложенные подзапросы сложно отлаживать.
  • Не всегда оптимизатор СУБД выбирает лучший план выполнения.
Проверить по документации: современные оптимизаторы MySQL и PostgreSQL часто преобразуют коррелированные подзапросы в JOIN автоматически. Конкретная производительность зависит от версии СУБД и наличия индексов.