SQL GROUP BY и HAVING: фильтр по агрегату
GROUP BY объединяет строки с одинаковыми значениями полей и вычисляет агрегаты для каждой группы. WHERE фильтрует строки до группировки, а HAVING — готовые группы, например оставляет только категории, где COUNT(*) > 1.
Найти клиентов с несколькими заказами
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(*), потому что агрегат вычисляется после отбора исходных строк.
Сначала отфильтровать строки, затем группы
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 оставляет группы с двумя и более подходящими строками.
Этап | Клауза | Пример |
|---|---|---|
Отбор исходных строк |
|
|
Формирование групп |
|
|
Отбор групп по агрегату |
|
|
Можно ли использовать несколько условий HAVING?
Да, объедините их через AND/OR, например HAVING COUNT(*) > 1 AND SUM(amount) > 100.
Как показать группы без фильтра по агрегату?
Уберите HAVING; оставьте GROUP BY и нужные агрегатные выражения в SELECT.