ПрограммированиеSQL аналитик

Поясните различия между HAVING и WHERE в SQL. Для чего нужен каждый из них, как они взаимодействуют с агрегатными функциями, и как избежать распространённых ошибок при их использовании?

Проходите собеседования с ИИ помощником Hintsage

Ответ

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

  • WHERE: нельзя использовать агрегатные функции (SUM, AVG и др.), так как фильтрация происходит ДО группировки.
  • HAVING: можно использовать агрегатные функции, так как фильтрация выполняется ПОСЛЕ группировки.

Пример:

-- Получить отделы с суммарной зарплатой больше 50000, исключая уволенных сотрудников SELECT department, SUM(salary) as total FROM employees WHERE status = 'active' GROUP BY department HAVING SUM(salary) > 50000;

Здесь:

  • WHERE status = 'active' — уберёт уволенных до расчёта сумм по отделам;
  • HAVING SUM(salary) > 50000 — покажет только те отделы, где общая зарплата превышает 50000.

Вопрос с подвохом

Можно ли использовать агрегатные функции в WHERE?

Ошибка: пытаются написать WHERE SUM(amount) > 100, но так нельзя — агрегатные функции применяются ТОЛЬКО в HAVING.

Пример (НЕправильно):

SELECT customer_id, SUM(amount) FROM orders WHERE SUM(amount) > 100 GROUP BY customer_id -- ERROR: неверное использование SUM() в WHERE

Правильно:

SELECT customer_id, SUM(amount) FROM orders GROUP BY customer_id HAVING SUM(amount) > 100;

Примеры реальных ошибок из-за незнания тонкостей темы


История

Разработка CRM. Попытка отфильтровать клиентов с количеством заказов >5 через WHERE COUNT(order_id) > 5. Запрос не работал. Итог: количество клиентов в отчёте некорректно, так как COUNT нельзя использовать в WHERE.


История

Бизнес-аналитика. Вместо фильтрации неактивных товаров в WHERE использовали HAVING. Результат: агрегирование "пустых" групп и медленный SQL. Исправлено переносом фильтра по статусу в WHERE.


История

Сложный отчет. Использовали HAVING без GROUP BY для фильтрации отдельных строк. В некоторых СУБД это вызывает ошибку, в других — неочевидное поведение. Вывод: HAVING должен идти после группировки и для агрегатных условий.