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

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

Ответ

Ключевое различие между WHERE и HAVING заключается в этапе выполнения запроса, на котором происходит фильтрация, и в типе данных, к которым она применяется.

Критерий WHERE HAVING
Этап выполнения Фильтрует строки ДО группировки (GROUP BY). Фильтрует группы или агрегированные результаты ПОСЛЕ группировки (GROUP BY).
Применяется к Отдельным записям (строкам) исходной таблицы. Агрегированным значениям (результатам функций COUNT, SUM, AVG, MIN, MAX) или сгруппированным столбцам.
Использование с агрегатными функциями Не может содержать агрегатные функции (если только они не в подзапросе). Может и обычно содержит агрегатные функции.
Обязательность GROUP BY Может использоваться без GROUP BY. Требует наличия GROUP BY (кроме редких случаев агрегации по всей таблице).

Логический порядок выполнения запроса: FROMWHEREGROUP BYHAVINGSELECTORDER BY

Наглядные примеры:

-- Пример 1: WHERE (фильтрация строк перед группировкой)
-- Задача: Найти среднюю зарплату по отделам, но только для сотрудников с зарплатой > 50000.
SELECT 
    DepartmentID,
    AVG(Salary) AS AvgSalary
FROM Employees
WHERE Salary > 50000  -- Сначала отфильтровываем ВСЕХ сотрудников с низкой зарплатой
GROUP BY DepartmentID;
-- Здесь AVG() считается только по оставшимся (высокооплачиваемым) сотрудникам в каждом отделе.

-- Пример 2: HAVING (фильтрация после группировки)
-- Задача: Найти отделы, в которых средняя зарплата превышает 70000.
SELECT 
    DepartmentID,
    AVG(Salary) AS AvgSalary
FROM Employees
GROUP BY DepartmentID          -- Сначала группируем всех сотрудников по отделам и считаем среднюю зарплату
HAVING AVG(Salary) > 70000;   -- Затем отфильтровываем те группы (отделы), где средняя зарплата > 70000

-- Пример 3: Комбинирование WHERE и HAVING
-- Задача: Найти отделы с более чем 5 сотрудниками, но учитывать только сотрудников, принятых после 2020 года.
SELECT 
    DepartmentID,
    COUNT(*) AS EmployeeCount
FROM Employees
WHERE HireDate > '2020-01-01'  -- 1. Фильтруем строки: берем только новых сотрудников
GROUP BY DepartmentID          -- 2. Группируем оставшихся по отделам
HAVING COUNT(*) > 5;           -- 3. Фильтруем группы: оставляем отделы с >5 новыми сотрудниками

Простое правило:

  • Используйте WHERE, когда условие фильтрации относится к данным в исходной таблице (например, Salary, HireDate).
  • Используйте HAVING, когда условие фильтрации основано на результате вычисления по группе (например, COUNT(*), AVG(Salary)).