← Назад к вопросам

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

2.3 Middle🔥 212 комментариев
#ASP.NET и Web API#Основы C# и .NET

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Подзапрос в 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;

Практические рекомендации

  1. Для простых сравнений с одним значением используйте скалярные подзапросы.
  2. Для проверки существования данных предпочитайте EXISTS вместо IN.
  3. При работе с агрегациями по группам часто эффективнее использовать коррелированные подзапросы.
  4. Если подзапрос становится слишком сложным, рассмотрите переход на CTE или временные таблицы.
  5. Всегда проверяйте план выполнения запроса: современные оптимизаторы SQL часто преобразуют подзапросы в JOIN.

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

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