Ответ
Ключевое различие между WHERE и HAVING заключается в этапе выполнения запроса, на котором происходит фильтрация, и в типе данных, к которым она применяется.
| Критерий | WHERE |
HAVING |
|---|---|---|
| Этап выполнения | Фильтрует строки ДО группировки (GROUP BY). |
Фильтрует группы или агрегированные результаты ПОСЛЕ группировки (GROUP BY). |
| Применяется к | Отдельным записям (строкам) исходной таблицы. | Агрегированным значениям (результатам функций COUNT, SUM, AVG, MIN, MAX) или сгруппированным столбцам. |
| Использование с агрегатными функциями | Не может содержать агрегатные функции (если только они не в подзапросе). | Может и обычно содержит агрегатные функции. |
| Обязательность GROUP BY | Может использоваться без GROUP BY. |
Требует наличия GROUP BY (кроме редких случаев агрегации по всей таблице). |
Логический порядок выполнения запроса:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER 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)).