SQL GROUP BY и HAVING: фильтр по агрегату

Категория: Postgresql · Язык: SQL · Обновлено:

GROUP BY объединяет строки с одинаковыми значениями полей и вычисляет агрегаты для каждой группы. WHERE фильтрует строки до группировки, а HAVING — готовые группы, например оставляет только категории, где COUNT(*) > 1.

Найти клиентов с несколькими заказами

SQL
CREATE TEMP TABLE orders (customer_id int, amount numeric);
INSERT INTO orders VALUES (1, 10), (1, 20), (2, 15);

SELECT customer_id, COUNT(*) AS orders_count, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
HAVING COUNT(*) > 1
ORDER BY customer_id;

Вернётся только клиент 1: у него две записи. WHERE не может фильтровать COUNT(*), потому что агрегат вычисляется после отбора исходных строк.

Сначала отфильтровать строки, затем группы

SQL
WITH orders(customer_id, amount) AS (VALUES (1, 10), (1, 20), (2, 15))
SELECT customer_id, COUNT(*) AS paid_count
FROM orders
WHERE amount >= 10
GROUP BY customer_id
HAVING COUNT(*) >= 2;

Здесь WHERE исключает строки дешевле 10 до подсчёта; HAVING оставляет группы с двумя и более подходящими строками.

Этап

Клауза

Пример

Отбор исходных строк

WHERE

WHERE amount >= 10

Формирование групп

GROUP BY

GROUP BY customer_id

Отбор групп по агрегату

HAVING

HAVING COUNT(*) > 1

Можно ли использовать несколько условий HAVING?

Да, объедините их через AND/OR, например HAVING COUNT(*) > 1 AND SUM(amount) > 100.

Как показать группы без фильтра по агрегату?

Уберите HAVING; оставьте GROUP BY и нужные агрегатные выражения в SELECT.