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