Что такое оператор HAVING в SQL?

«Что такое оператор HAVING в SQL?» — вопрос из категории Базы данных, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

HAVING — это оператор SQL, используемый для фильтрации групп записей, созданных оператором GROUP BY. В то время как WHERE фильтрует строки перед группировкой, HAVING применяется к агрегированным результатам после группировки.

Основное отличие HAVING от WHERE:

Критерий WHERE HAVING
Время выполнения До группировки (GROUP BY) После группировки (GROUP BY)
Работа с агрегатами Не может использовать агрегатные функции (SUM, COUNT, AVG) Может и часто использует агрегатные функции
Цель Фильтрация исходных строк Фильтрация сгруппированных результатов

Пример использования:

-- Найти отделы, в которых работает больше 5 сотрудников
SELECT DepartmentID, COUNT(*) AS EmployeeCount
FROM Employees
GROUP BY DepartmentID
HAVING COUNT(*) > 5;

-- Найти отделы со средней зарплатой выше 100 000
SELECT DepartmentID, AVG(Salary) AS AvgSalary
FROM Employees
GROUP BY DepartmentID
HAVING AVG(Salary) > 100000;

Аналог в LINQ (C#):

В LINQ нет отдельного ключевого слова HAVING. Его роль выполняет метод Where, применяемый после GroupBy.

var departmentsWithManyEmployees = employees
    .GroupBy(e => e.DepartmentId)
    .Where(g => g.Count() > 5) // Это аналог HAVING COUNT(*) > 5
    .Select(g => new {
        DepartmentId = g.Key,
        EmployeeCount = g.Count(),
        AverageSalary = g.Average(e => e.Salary)
    });

// Можно фильтровать и по другим агрегатам
var highPayingDepartments = employees
    .GroupBy(e => e.DepartmentId)
    .Where(g => g.Average(e => e.Salary) > 100000) // Аналог HAVING AVG(Salary) > 100000
    .Select(g => new { DepartmentId = g.Key, AvgSalary = g.Average(e => e.Salary) });

Важные нюансы:

  1. HAVING почти всегда используется вместе с GROUP BY.
  2. В условии HAVING можно ссылаться на псевдонимы (алиасы) столбцов из SELECT, но это зависит от СУБД. Лучше использовать саму агрегатную функцию для переносимости.
  3. В одном запросе можно использовать и WHERE, и HAVING:
    -- Найти отделы (кроме отдела с ID=1), где работает больше 3 сотрудников
    SELECT DepartmentID, COUNT(*)
    FROM Employees
    WHERE DepartmentID != 1 -- Фильтрация ДО группировки
    GROUP BY DepartmentID
    HAVING COUNT(*) > 3; -- Фильтрация ПОСЛЕ группировки