Короткий ответ
WHERE фильтрует строки до GROUP BY, а HAVING фильтрует группы после агрегации. Поэтому условие на SUM или COUNT размещают в HAVING.
Как это работает подробнее
Логический порядок обработки запроса: FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY. На этапе WHERE агрегатные значения ещё не вычислены.
Ранний фильтр уменьшает объём данных для соединения и группировки. Если условие относится к отдельной строке, его обычно выгоднее и понятнее записать в WHERE.
Пример кода
query.sql
SELECT customer_id, SUM(amount) AS total_amount
FROM orders
WHERE order_date >= DATE '2024-01-01'
GROUP BY customer_id
HAVING SUM(amount) > 1000
ORDER BY total_amount DESC;Что использовать на практике
- WHERE. Ограничивайте период, статус исходной строки и другие неагрегированные признаки.
- HAVING. Оставляйте группы по условиям вроде
SUM(amount) > 1000илиCOUNT(*) > 5.
Подводные камни
- Агрегат в WHERE. Запись
WHERE SUM(amount) > 1000некорректна, потому что сумма ещё не рассчитана. - Поздняя фильтрация. Перенос обычного условия в
HAVINGможет заставить СУБД обработать лишние строки.