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 — итоги после. Порядок частей: WHERE → GROUP BY → HAVING → ORDER BY.
| Условие | Что фильтрует |
WHERE | отдельные строки до группировки |
HAVING | группы по агрегату после группировки |
Итог
GROUP BY столбецобъединяет строки в группы; агрегаты считаются внутри каждой группы.- При группировке в
SELECTдопустимы только столбцы группировки и агрегаты. WHEREфильтрует строки до группировки,HAVING— группы после неё.