GROUP BY и HAVING

Считаем агрегаты не по всей таблице, а по каждой группе отдельно.

GROUP BY делит строки на группы по значению столбца, а агрегатные функции считаются внутри каждой группы.

GROUP BY — итоги по категориям

В прошлом уроке мы считали сумму по всей таблице. Чаще нужны итоги по каждой категории: сколько продано каждого товара. GROUP BY product объединяет строки с одинаковым товаром в группу, и агрегаты считаются для каждой группы.

CREATE TABLE sales (id INTEGER PRIMARY KEY, product TEXT, amount INTEGER);

INSERT INTO sales (product, amount) VALUES
    ('Книга', 500), ('Книга', 300),
    ('Ручка',  50), ('Ручка',  70), ('Тетрадь', 200);

SELECT product,
       COUNT(*)    AS продаж,
       SUM(amount) AS выручка
FROM sales
GROUP BY product
ORDER BY выручка DESC;

Вывод:

Книга|2|800
Тетрадь|1|200
Ручка|2|120

Каждая строка результата — это одна группа товара со своими итогами. «Книга» дала 800, «Тетрадь» — 200 за одну продажу, «Ручка» — 120 за две.

Правило: в SELECT — только группа или агрегат

Когда есть GROUP BY, в списке SELECT можно использовать только столбцы из GROUP BY и агрегатные функции. Логично: внутри группы много строк, и взять «просто amount» неоднозначно — какой из нескольких? Поэтому либо группируем по нему, либо агрегируем (SUM, MAX и т.д.).

HAVING — фильтр групп

WHERE отбирает строки до группировки, а отфильтровать сами группы по агрегату нельзя через WHERE — для этого есть HAVING. Оставим только товары с выручкой больше 150:

CREATE TABLE sales (id INTEGER PRIMARY KEY, product TEXT, amount INTEGER);

INSERT INTO sales (product, amount) VALUES
    ('Книга', 500), ('Книга', 300),
    ('Ручка',  50), ('Ручка',  70), ('Тетрадь', 200);

SELECT product, SUM(amount) AS выручка
FROM sales
GROUP BY product
HAVING SUM(amount) > 250
ORDER BY выручка DESC;

Вывод:

Книга|800

Из трёх групп условие HAVING SUM(amount) > 250 прошла только «Книга» (800). «Тетрадь» (200) и «Ручка» (120) отсеялись.

WHERE и HAVING вместе

Их часто используют в одном запросе, и важно не путать: WHERE фильтрует исходные строки до группировки, HAVING — итоги после. Порядок частей: WHEREGROUP BYHAVINGORDER BY.

УсловиеЧто фильтрует
WHEREотдельные строки до группировки
HAVINGгруппы по агрегату после группировки

Итог

  • GROUP BY столбец объединяет строки в группы; агрегаты считаются внутри каждой группы.
  • При группировке в SELECT допустимы только столбцы группировки и агрегаты.
  • WHERE фильтрует строки до группировки, HAVING — группы после неё.
Проверьте себя
1. Что делает GROUP BY product?
AСортирует по товару
BОбъединяет строки с одинаковым товаром в группу для подсчёта агрегатов
CУдаляет дубликаты товаров
DСчитает все строки таблицы
2. Чем HAVING отличается от WHERE?
AНичем
BWHERE фильтрует строки до группировки, HAVING — группы по агрегату после
CHAVING работает только без GROUP BY
DWHERE можно использовать с агрегатами, а HAVING — нет
3. Какие столбцы можно ставить в SELECT при наличии GROUP BY?
AЛюбые столбцы таблицы
BТолько столбцы из GROUP BY и агрегатные функции
CТолько агрегаты
DНи один столбец
Поддержать проект