Stage 5. GROUP BY и HAVING для бизнес-метрик
Когда бизнес спрашивает “какая выручка?” или “сколько заказов у каждого клиента?”, обычного SELECT недостаточно. Нужна агрегация: превратить много строк в компактные итоги. Для этого используются GROUP BY и HAVING.
Что такое GROUP BY
GROUP BY объединяет строки в группы по указанному полю (или нескольким полям). После этого по каждой группе можно считать агрегаты: COUNT, SUM, AVG, MIN, MAX.
Пример:
SELECT user_id,
COUNT(*) AS orders_count,
SUM(amount) AS total_amount
FROM orders
WHERE status = 'PAID'
GROUP BY user_id;
Что происходит:
- Берем только
PAIDизWHERE. - Делим строки на группы по
user_id. - Для каждой группы считаем число заказов и сумму.
Что такое HAVING
HAVING фильтрует уже готовые группы после GROUP BY.
SELECT user_id,
SUM(amount) AS total_amount
FROM orders
WHERE status = 'PAID'
GROUP BY user_id
HAVING SUM(amount) >= 1000;
Смысл: оставить только тех пользователей, у кого суммарно оплачено не меньше 1000.
Ключевая разница:
WHEREфильтрует строки до группировки;HAVINGфильтрует группы после группировки.
Термины и ключевые слова в одной таблице
| Ключевое слово | Роль | Пример |
|---|---|---|
GROUP BY | Группирует строки по ключу | GROUP BY user_id |
COUNT(*) | Считает строки в группе | Число заказов |
SUM(amount) | Суммирует значения в группе | Выручка |
HAVING | Отсеивает группы по условию | HAVING SUM(amount) > 1000 |
Пример с результатом
SELECT user_id,
COUNT(*) AS orders_count,
SUM(amount) AS total_amount
FROM orders
WHERE status = 'PAID'
GROUP BY user_id
ORDER BY total_amount DESC;
Результат:
| user_id | orders_count | total_amount |
|---|---|---|
| 1 | 5 | 4700.00 |
| 2 | 2 | 1400.00 |
| 3 | 1 | 300.00 |
Частые ошибки новичков
- Используют
HAVING, когда нужен обычныйWHERE. - Пытаются выбрать поле в
SELECT, которое не агрегировано и не входит вGROUP BY. - Группируют по слишком “точному” полю (например полный timestamp), получая тысячи мелких групп.
Практический сценарий: топ-клиенты за месяц
SELECT user_id,
SUM(amount) AS revenue
FROM orders
WHERE status = 'PAID'
AND created_at >= DATE '2026-05-01'
AND created_at < DATE '2026-06-01'
GROUP BY user_id
HAVING SUM(amount) >= 1000
ORDER BY revenue DESC;
Это готовая база для отчета “кто сделал наибольшую выручку за период”.
Практика перед следующим уроком
Сначала напишите простой SELECT по оплаченных заказам. Затем добавьте GROUP BY. Потом добавьте HAVING. На каждом шаге проверяйте, как меняется результат: строки → группы → отфильтрованные группы.