Что такое подзапрос в SQL?

Ответ

Подзапрос (subquery) — это SQL-запрос, вложенный внутрь другого основного запроса (SELECT, INSERT, UPDATE, DELETE). Его результат используется внешним запросом как условие, источник данных или вычисляемое значение.

Основные типы и использование:

  • Скалярный подзапрос (возвращает одно значение):
    SELECT name FROM employees
    WHERE salary > (SELECT AVG(salary) FROM employees);
  • Подзапрос, возвращающий множество строк (используется с IN, ANY, ALL):
    SELECT name FROM departments
    WHERE id IN (SELECT department_id FROM projects WHERE budget > 100000);
  • Подзапрос в качестве таблицыFROM):
    SELECT dept_name, avg_sal
    FROM (SELECT department_id, AVG(salary) as avg_sal FROM employees GROUP BY department_id) AS dept_stats
    WHERE avg_sal > 50000;

Коррелированные vs. Некоррелированные:

  • Некоррелированный выполняется один раз независимо от внешнего запроса.
  • Коррелированный выполняется для каждой строки внешнего запроса, ссылаясь на его значения (может быть менее производительным).

Производительность: Часто подзапрос можно переписать с использованием JOIN, что может быть эффективнее, особенно для коррелированных подзапросов. Выбор зависит от оптимизатора СУБД и структуры данных.

Ответ 18+ 🔞

Слушай, давай разберёмся с этими подзапросами, а то у некоторых от одного слова голова квадратная становится. Представь, что это как матрёшка, только в SQL. Берёшь один запрос и засовываешь его прямо в живот другому. Внешний запрос потом этим результатом пользуется — как условием, как данными или просто как цифрой для расчётов. Всё просто, ёпта.

Какие они бывают и куда их пихают:

  • Подзапрос-одиночка (скалярный). Возвращает одно-единственное значение, одну ячейку. Идеально для сравнений.

    SELECT name FROM employees
    WHERE salary > (SELECT AVG(salary) FROM employees);

    Тут внутренний запрос (SELECT AVG...) посчитает среднюю зарплату по больнице один раз, и внешний запрос с этим числом уже работает. Удобно, правда?

  • Подзапрос-список. Возвращает целый столбик значений, несколько строк. Тут уже нужны специальные операторы вроде IN.

    SELECT name FROM departments
    WHERE id IN (SELECT department_id FROM projects WHERE budget > 100000);

    Перевод на человеческий: «Дай мне названия отделов, у которых есть проекты с бюджетом больше ста тысяч». Внутренний запрос выплёвывает кучу department_id, а внешний по этому списку отфильтровывает.

  • Подзапрос как целая виртуальная таблица. Самый хардкор — когда результат подзапроса используется прямо как источник данных в FROM. Выглядит страшновато, но мощно.

    SELECT dept_name, avg_sal
    FROM (SELECT department_id, AVG(salary) as avg_sal FROM employees GROUP BY department_id) AS dept_stats
    WHERE avg_sal > 50000;

    Сначала мы создаём временную таблицу dept_stats со средней зарплатой по отделам, а потом из неё уже выбираем только те, где средняя зарплата выше 50к. Ёперный театр, а не подход!

Важный момент, блядь: коррелированные vs. некоррелированные.

  • Некоррелированный — как самостоятельная песенка. Выполнился один раз в начале, отдал результат и отдыхает. Как в первых двух примерах.
  • Коррелированный — это уже зависимая хуйня. Он выполняется заново для КАЖДОЙ строки внешнего запроса, потому что ссылается на его поля. Представь, что для каждого сотрудника ты отдельно бегаешь в подзапрос что-то проверять. Производительность от этого может накрыться медным тазом, если данных овердохуища.

Про производительность: Часто эту всю конструкцию можно переписать на JOIN. Иногда JOIN быстрее, особенно для коррелированных подзапросов. А иногда оптимизатор базы данных сам всё по-умному преобразует. Так что, чувак, смотри по ситуации, смотри на планы выполнения и не бзди экспериментировать. Главное — чтобы работало и не тормозило как хуй в пальто.