Введение
При работе с базами данных часто бывает нужно использовать результат одного запроса внутри другого.
Например, сначала нужно узнать 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';
- Он возвращает ID группы.
- Затем основной запрос находит всех студентов с этим
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.
Частые ошибки
- Использование
=с подзапросом, который возвращает несколько строк. - Отсутствие псевдонима у подзапроса в
FROM. - Использование нескольких столбцов там, где ожидается одно значение.
- Слишком сложные коррелированные подзапросы, которые могут работать медленно.
Итоги
- Подзапрос — это SQL-запрос внутри другого запроса.
- Сначала выполняется внутренний запрос, затем внешний.
- Подзапросы можно использовать в
WHERE,SELECT,FROMиHAVING. - Если подзапрос возвращает несколько значений, используется оператор IN.
- Коррелированные подзапросы выполняются для каждой строки внешнего запроса.