HAVING
HAVING фильтрует группы после GROUP BY и вычисления агрегатов.
SELECT user_id,
COUNT(*) AS order_count,
SUM(total) AS amount
FROM orders
WHERE state = 'PAID'
GROUP BY user_id
HAVING SUM(total) >= 10000;WHERE оставил только оплаченные заказы, HAVING — пользователей с достаточной общей суммой.
Не переносить обычный фильтр без причины
-- Лучше фильтровать строки раньше:
WHERE state = 'PAID'
-- А не полагаться на поздний фильтр:
HAVING state = 'PAID'Второй вариант может быть запрещен, неоднозначен или требовать добавления state в ключ группировки. Оптимизатор иногда проталкивает безопасные условия, но семантику нужно выражать явно.
Без GROUP BY
Запрос без GROUP BY рассматривает весь вход как одну группу:
SELECT COUNT(*) AS order_count
FROM orders
HAVING COUNT(*) > 0;Он вернет одну строку, если есть заказы, иначе ни одной. Для простой проверки существования обычно понятнее EXISTS.
Ловушки
HAVING COUNT(column) = 0иHAVING COUNT(*) = 0различаются приNULLи outer join.- Псевдонимы из
SELECTвHAVINGподдерживаются не во всех диалектах. HAVINGне заменяетWHERE: поздняя фильтрация может увеличить объем группировки.
Связано: Оператор GROUP BY, Агрегатные функции, Условный оператор WHERE.
Вопросы
Главное отличие WHERE от HAVING? Первый фильтрует строки, второй — группы.
Можно ли использовать агрегат в WHERE? Не на том же уровне запроса; агрегация логически происходит позже.
Обязателен ли GROUP BY для HAVING? Нет, весь набор может быть одной группой.