В чем разница между предложениями WHERE и HAVING в SQL?

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

Ответ

Ключевое отличие заключается в моменте применения фильтрации в порядке выполнения SQL-запроса.

  • WHERE фильтрует строки до группировки (операция GROUP BY). Он работает с отдельными записями исходной таблицы.
  • HAVING фильтрует строки после группировки. Он работает с агрегированными результатами (группами), созданными GROUP BY.

Порядок выполнения SQL-запроса (упрощенно)

  1. FROM / JOIN (определение таблиц)
  2. WHERE (фильтрация строк на этом этапе)
  3. GROUP BY (группировка отфильтрованных строк)
  4. HAVING (фильтрация сгруппированных результатов)
  5. SELECT (выбор полей)
  6. ORDER BY (сортировка)

Практические примеры

Пример 1: WHERE (фильтрация до группировки)

"Найти среднюю зарплату по отделам, но только для сотрудников, работающих в компании больше года."

SELECT DepartmentId, AVG(Salary) as AvgSalary
FROM Employees
WHERE DATEDIFF(year, HireDate, GETDATE()) > 1 -- Фильтр применяется к КАЖДОМУ сотруднику
GROUP BY DepartmentId;

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

Пример 2: HAVING (фильтрация после группировки)

"Найти отделы, в которых средняя зарплата превышает 75000."

SELECT DepartmentId, AVG(Salary) as AvgSalary
FROM Employees
GROUP BY DepartmentId
HAVING AVG(Salary) > 75000; -- Фильтр применяется к РЕЗУЛЬТАТУ агрегации (к группам)

Здесь сначала вычисляется средняя зарплата для каждого отдела, а затем HAVING отбрасывает те группы (отделы), где это среднее значение не превышает 75000.

Пример 3: Совместное использование WHERE и HAVING

"Найти отделы, где средняя зарплата действующих сотрудников превышает 80000."

SELECT DepartmentId, AVG(Salary) as AvgSalary
FROM Employees
WHERE IsActive = 1 -- Сначала берем только активных сотрудников
GROUP BY DepartmentId
HAVING AVG(Salary) > 80000; -- Затем фильтруем результаты агрегации

Главное правило

  • Используйте WHERE для условий, основанных на данных отдельных строк (например, Salary > 50000, Name LIKE 'A%').
  • Используйте HAVING для условий, основанных на результатах агрегатных функций (SUM, AVG, COUNT, MIN, MAX) после группировки.