Перейти к содержанию

Введение

При работе с базами данных часто бывает нужно использовать результат одного запроса внутри другого.

Например, сначала нужно узнать ID группы, а потом с помощью этого ID найти всех студентов этой группы.

В таких случаях используется подзапрос.

Подзапрос (subquery) — это SQL-запрос, который находится внутри другого запроса.

Особенности подзапроса: - он записывается внутри другого запроса; - сначала выполняется внутренний запрос; - результат внутреннего запроса используется внешним запросом.

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


Общая структура подзапроса

Простейшая структура выглядит так:

SELECT столбцы
FROM таблица
WHERE столбец = (
    SELECT столбец
    FROM таблица
    WHERE условие
);

Как выполняется такой запрос: 1. Сначала выполняется внутренний запрос. 2. Он возвращает некоторое значение. 3. Это значение используется во внешнем запросе.


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

Подзапрос можно разместить в разных частях SQL-запроса: 1. WHERE — для фильтрации данных 2. FROM — как временную таблицу 3. SELECT — для вычисления значений 4. HAVING — для фильтрации результатов группировки


Подзапрос в WHERE

Это самый распространённый вариант использования подзапросов.

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

Пример

Найти студентов, которые учатся в группе ИС-21.

SELECT *
FROM Students
WHERE group_id = (
    SELECT id
    FROM Groups
    WHERE group_name = 'ИС-21'
);

Как работает этот запрос: 1. Сначала выполняется подзапрос:

SELECT id
FROM Groups
WHERE group_name = 'ИС-21';
  1. Он возвращает ID группы.
  2. Затем основной запрос находит всех студентов с этим group_id.

Подзапрос, возвращающий несколько значений (IN)

Иногда подзапрос возвращает несколько строк, а не одно значение.

В этом случае используется оператор IN.

Пример

Найти студентов, которые учатся на первом курсе.

SELECT *
FROM Students
WHERE group_id IN (
    SELECT id
    FROM Groups
    WHERE course = 1
);

Подзапрос вернёт несколько ID групп, а внешний запрос найдёт студентов из всех этих групп.


Подзапрос с операторами ANY и ALL

Эти операторы используются для сравнения значения с несколькими результатами подзапроса.

ANY

Условие будет истинным, если оно выполняется хотя бы для одного значения.

ALL

Условие будет истинным, если оно выполняется для всех значений.

Пример

Найти товары, цена которых выше всех товаров из категории 2.

SELECT *
FROM Products
WHERE price > ALL (
    SELECT price
    FROM Products
    WHERE category_id = 2
);

Сначала подзапрос получает все цены из категории 2,
а затем внешний запрос выбирает товары дороже всех этих значений.


Подзапрос в SELECT

Подзапрос можно использовать прямо в списке выводимых столбцов.

Он будет вычислять значение, которое появится в каждой строке результата.

Пример

SELECT name,
       (SELECT AVG(score) FROM Students) AS average_score
FROM Students;

Этот запрос: - выводит имя студента; - показывает средний балл всех студентов. Средний балл будет одинаковым для всех строк.


Подзапрос в FROM (временная таблица)

Подзапрос можно использовать как временную таблицу.

В этом случае внешний запрос работает с результатом подзапроса как с обычной таблицей.

Пример

SELECT *
FROM (
    SELECT group_id, COUNT(*) AS student_count
    FROM Students
    GROUP BY group_id
) AS group_stats
WHERE student_count > 5;

Что происходит: 1. Подзапрос считает количество студентов в каждой группе. 2. Результат становится временной таблицей group_stats. 3. Внешний запрос выбирает группы, где больше 5 студентов.

Важно:
подзапрос в FROM обязательно должен иметь псевдоним (имя таблицы).


Коррелированные подзапросы

Обычный подзапрос выполняется один раз.

Но иногда подзапрос зависит от данных каждой строки внешнего запроса.

Такой подзапрос называется коррелированным.

Он выполняется для каждой строки основного запроса.

Пример

Найти студентов, у которых балл выше среднего по их группе.

SELECT s.full_name
FROM Students s
WHERE s.score > (
    SELECT AVG(score)
    FROM Students
    WHERE group_id = s.group_id
);

Здесь подзапрос использует значение s.group_id из внешнего запроса.

Для каждой группы вычисляется своё среднее значение.


Разница между JOIN и подзапросом

Подзапрос JOIN
Часто проще написать Чаще работает быстрее
Удобен для фильтрации Удобен для объединения таблиц
Может быть вложенным Явно показывает связь таблиц

Во многих случаях одну и ту же задачу можно решить и подзапросом, и JOIN.


Частые ошибки

  1. Использование = с подзапросом, который возвращает несколько строк.
  2. Отсутствие псевдонима у подзапроса в FROM.
  3. Использование нескольких столбцов там, где ожидается одно значение.
  4. Слишком сложные коррелированные подзапросы, которые могут работать медленно.

Итоги

  • Подзапрос — это SQL-запрос внутри другого запроса.
  • Сначала выполняется внутренний запрос, затем внешний.
  • Подзапросы можно использовать в WHERE, SELECT, FROM и HAVING.
  • Если подзапрос возвращает несколько значений, используется оператор IN.
  • Коррелированные подзапросы выполняются для каждой строки внешнего запроса.