theory_01__SubQuery.md

Занятие 28Markdown100 строк

← К репозиторию занятия · 07__SubQuery__CTE/theory_01__SubQuery.md

Подзапросы (SubQuery) в MySQL:

Подзапрос — это SQL-запрос, вложенный внутрь другого SQL-запроса.

Он может использоваться в операторе SELECT, INSERT, UPDATE или DELETE, а также в выражениях WHERE, FROM и HAVING.

Пример подзапроса:

-- Найти имена сотрудников, работающих в отделе Продаж

SELECT name
FROM employees
WHERE department_id = (
    SELECT id
    FROM departments
    WHERE name = 'Sales'
);

В этом примере подзапрос сначала находит id отдела Sales, а затем внешний запрос ищет всех сотрудников этого отдела.

Где можно использовать подзапросы (SubQuery)?

Место использованияПримерОписание
SELECTSELECT name, salary,
(SELECT AVG(salary) FROM employes)
AS avg_salary FROM employees;
Подзапрос возвращает скалярное значение, используется как поле в SELECT.
FROMSELECT *
FROM (SELECT * FROM orders WHERE amount > 100) AS t_big_orders;
Подзапрос используется как временная таблица. Требуется псевдоним.
WHERESELECT name, salary
FROM employes
WHERE employes > (SELECT AVG(salary) FROM employes);
Подзапрос используется как фильтр — одно из самых распространённых применений.
HAVINGSELECT customer_id, COUNT(*)
FROM orders
GROUP BY customer_id
HAVING COUNT(*) > (
   SELECT AVG(cnt)
   FROM (
      SELECT COUNT(*) AS cnt
      FROM orders
      GROUP BY customer_id) AS sub
);
Подзапрос используется для фильтрации агрегатных значений.

Градация подзапросов по возвращаемому значению

Тип подзапросаОписаниеГде применяется
СкалярныйВозвращает одно значениеSELECT, WHERE, HAVING
Список значенийОдин столбец (массив)IN, NOT IN
Множественные значенияНесколько столбцов и строк, сравниваются как спискиWHERE (col1, col2) IN (...)
ТабличныйПолноценная таблица, используется как временнаяFROM, JOIN, WITH

Примеры

🟩 Скалярный подзапрос
SELECT name
FROM customers
WHERE id = (
    SELECT MIN(id)
    FROM customers
);
🟦 Список значений
SELECT name
FROM customers
WHERE id IN (
    SELECT customer_id
    FROM orders
);
🟨 Множественные значения
SELECT *
FROM employees
WHERE (department_id, job_title) IN (
    SELECT dept_id, title
    FROM department_roles
);
🟪 Табличный подзапрос
SELECT d.name, COUNT(*) AS employee_count
FROM (
    SELECT * FROM employees
    WHERE hired_date >= '2020-01-01'
) AS recent_hires
JOIN departments d ON recent_hires.department_id = d.id
GROUP BY d.name;

✅ Плюсы подзапросов

ПлюсОбъяснение
ЧитаемостьУпрощает структуру запроса, особенно при вложенной логике.
ИнкапсуляцияИзолирует отдельную часть логики в виде "чёрного ящика".
ГибкостьПозволяет выполнять динамические вычисления и фильтрацию.
Без временных таблицНе требует отдельного представления или временной таблицы.

❌ Минусы подзапросов

МинусОбъяснение
Медленнее JOINЧасто JOIN работает быстрее, особенно при наличии индексов.
Коррелированные подзапросыВыполняются для каждой строки внешнего запроса — это дорого по ресурсам.
Плохо читаемые вложенностиСложные подзапросы трудны для отладки и понимания.
Ограничения MySQLВ некоторых случаях MySQL накладывает ограничения на использование подзапросов (особенно в старых версиях).