WHERE против HAVING

Чем WHERE отличается от HAVING — и почему это не взаимозаменяемые фильтры.

WHERE фильтрует отдельные строки до группировки, HAVING — целые группы после агрегации.

Суть вопроса

Оба ключевых слова фильтруют, но на разных стадиях. WHERE отсекает строки до GROUP BY — в нём нельзя использовать агрегатные функции. HAVING работает уже с готовыми группами — в нём агрегаты как раз и нужны.

Один запрос — оба фильтра

Посчитаем сумму заказов по клиентам, но: (1) учитываем только заказы дороже 100 — это про строки, значит WHERE; (2) оставляем клиентов, у которых итог больше 400 — это про группы, значит HAVING.

CREATE TABLE orders (
    id       INTEGER PRIMARY KEY,
    customer TEXT,
    amount   INTEGER
);

INSERT INTO orders (customer, amount) VALUES
    ('Аня',   500),
    ('Аня',   50),
    ('Борис', 300),
    ('Борис', 200),
    ('Вера',  90);

SELECT customer, SUM(amount) AS total
FROM orders
WHERE amount > 100          -- фильтр строк: заказ 'Аня 50' и 'Вера 90' выпадают
GROUP BY customer
HAVING SUM(amount) > 400    -- фильтр групп: остаётся только тот, у кого итог > 400
ORDER BY customer;

Вывод:

Аня|500
Борис|500

Аня: учтён только заказ 500 (заказ 50 отсёк WHERE), итог 500 — проходит HAVING. Борис: 300+200=500 — тоже проходит. Вера: единственный заказ 90 отсёк WHERE, группа исчезла ещё до HAVING.

Типичная ошибка

Поставить агрегат в WHERE — частая ошибка. Такой запрос упадёт:

SELECT customer, SUM(amount)
FROM orders
WHERE SUM(amount) > 400   -- ОШИБКА: агрегат в WHERE
GROUP BY customer;

СУБД ответит ошибкой вроде «misuse of aggregate function SUM()». Условие на сумму — это про группу, ему место в HAVING.

Памятка

ПризнакWHEREHAVING
Когда работаетдо группировкипосле группировки
Над чемнад строкаминад группами
Агрегатынельзяможно и нужно
Без GROUP BYобычный фильтр строкредко, фильтр по агрегату всей таблицы

Итог

  • WHERE — фильтр строк до агрегации, без агрегатных функций.
  • HAVING — фильтр групп после агрегации, с агрегатами.
  • Если условие можно проверить на уровне строки — оно в WHERE; так быстрее, ведь до группировки доходит меньше данных.
Проверьте себя
1. Чем WHERE отличается от HAVING?
AWHERE для чисел, HAVING для строк
BWHERE фильтрует строки до группировки, HAVING — группы после
CЭто полные синонимы
DHAVING выполняется до WHERE
2. Можно ли использовать SUM(amount) > 400 в WHERE?
AДа, без ограничений
BНет, агрегаты в WHERE недопустимы — нужно HAVING
CТолько в SQLite
DТолько если добавить DISTINCT
3. Почему фильтр amount > 100 лучше держать в WHERE, а не в HAVING?
AHAVING не поддерживает сравнение
BWHERE отсекает строки раньше, до группировки меньше данных
CРазницы нет вообще
DWHERE автоматически создаёт индекс
Поддержать проект