Что такое подзапрос в SQL?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Подзапрос в SQL
Подзапрос (subquery) — это SQL-запрос, вложенный внутри другого запроса. Он позволяет выполнить сложные операции с данными, использующие промежуточные результаты. Подзапрос всегда заключен в круглые скобки и может использоваться в различных частях основного запроса: в SELECT, FROM, WHERE, JOIN и других операторах.
Ключевые особенности подзапросов:
- Зависимый или независимый: подзапрос может быть коррелированным (зависимым) или некоррелированным (независимым).
- Ограничение одной строки: некоторые подзапросы должны возвращать только одну строку (например, при использовании с операторами сравнения).
- Возможность использования агрегатных функций: подзапросы часто используются для сравнения с агрегированными значениями.
Основные типы подзапросов
1. Подзапросы в WHERE (самый частый случай)
SELECT EmployeeName, Salary
FROM Employees
WHERE Salary > (
SELECT AVG(Salary)
FROM Employees
);
Этот некоррелированный подзапрос вычисляет среднюю зарплату всех сотрудников, а затем выбирает тех, у которых зарплата выше средней.
2. Коррелированные подзапросы
SELECT DepartmentName, EmployeeName, Salary
FROM Employees e
WHERE Salary > (
SELECT AVG(Salary)
FROM Employees
WHERE DepartmentId = e.DepartmentId
);
Коррелированный подзапрос ссылается на столбец внешнего запроса (e.DepartmentId). Здесь для каждого сотрудника вычисляется средняя зарплата в его отделе, и выбираются сотрудники с зарплатой выше средней в своем отделе.
3. Подзапросы в FROM (производные таблицы)
SELECT DeptName, AvgSalary
FROM (
SELECT DepartmentId, AVG(Salary) AS AvgSalary
FROM Employees
GROUP BY DepartmentId
) AS DeptStats
JOIN Departments d ON d.Id = DeptStats.DepartmentId;
Подзапрос создает временную таблицу DeptStats, которая затем используется в JOIN.
4. Подзапросы в SELECT (скалярные подзапросы)
SELECT EmployeeName,
Salary,
(SELECT AVG(Salary) FROM Employees) AS CompanyAvgSalary
FROM Employees;
Подзапрос в SELECT должен возвращать единственное значение (скаляр). Здесь он добавляет столбец с средней зарплатой компании для каждой строки.
Примеры операторов с подзапросом
IN и NOT IN
SELECT ProductName
FROM Products
WHERE CategoryId IN (
SELECT CategoryId
FROM Categories
WHERE IsActive = 1
);
EXISTS и NOT EXISTS
SELECT DepartmentName
FROM Departments d
WHERE EXISTS (
SELECT 1
FROM Employees e
WHERE e.DepartmentId = d.Id AND e.Salary > 100000
);
EXISTS проверяет наличие хотя бы одной строки в подзапрос. Ключевое отличие от IN: EXISTS часто более эффективен для коррелированных проверок.
ALL, ANY/SOME
SELECT EmployeeName
FROM Employees
WHERE Salary > ALL (
SELECT Salary
FROM Employees
WHERE DepartmentId = 3
);
ALL требует, чтобы значение было больше всех значений подзапроса.
Сравнение с JOIN
Подзапросы и JOIN часто могут решать одинаковые задачи, но имеют разные особенности:
-- Подзапрос
SELECT Name
FROM Customers
WHERE Id IN (
SELECT CustomerId
FROM Orders
WHERE Total > 1000
);
-- JOIN
SELECT DISTINCT c.Name
FROM Customers c
JOIN Orders o ON c.Id = o.CustomerId
WHERE o.Total > 1000;
Когда использовать подзапросы:
- Для сравнения с агрегированными значениями (
AVG,MAX) - Когда нужна проверка существования (
EXISTS) - Для создания промежуточных таблиц сложной структуры
- Когда логика требует последовательного выполнения запросов
Ограничения и оптимизация
- Производительность: Коррелированные подзапросы могут быть менее эффективными, поскольку выполняются для каждой строки внешнего запроса.
- Читаемость: Сложные подзапросы могут ухудшать читаемость кода.
- Современные альтернативы: Вместо подзапросов в
FROMчасто лучше использовать CTE (Common Table Expressions):
WITH DeptStats AS (
SELECT DepartmentId, AVG(Salary) AS AvgSalary
FROM Employees
GROUP BY DepartmentId
)
SELECT DeptName, AvgSalary
FROM DeptStats
JOIN Departments d ON d.Id = DeptStats.DepartmentId;
Практические рекомендации
- Для простых сравнений с одним значением используйте скалярные подзапросы.
- Для проверки существования данных предпочитайте
EXISTSвместоIN. - При работе с агрегациями по группам часто эффективнее использовать коррелированные подзапросы.
- Если подзапрос становится слишком сложным, рассмотрите переход на CTE или временные таблицы.
- Всегда проверяйте план выполнения запроса: современные оптимизаторы SQL часто преобразуют подзапросы в
JOIN.
Подзапросы остаются мощным инструментом для решения сложных задач выборки данных, особенно когда требуется сравнение с динамически вычисляемыми значениями или проверка сложных условий.