АгрегатыСредний
ROLLUP
Расширение GROUP BY, которое кроме обычных групп считает промежуточные итоги и общий итог в одном запросе. Есть в PostgreSQL.
Синтаксис
SELECT col1, col2, AGG(col3) FROM table GROUP BY ROLLUP (col1, col2);Объяснение
ROLLUP строит иерархию итогов: для GROUP BY ROLLUP(a, b) вернутся строки по (a, b), промежуточные итоги по (a) и общий итог по всей таблице. В итоговых строках вместо «свёрнутой» колонки стоит NULL.
Чтобы отличить настоящий NULL в данных от NULL итоговой строки, используй GROUPING(col): она возвращает 1 для итоговой строки.
Похожие конструкции: CUBE(a, b) считает итоги по всем комбинациям колонок, GROUPING SETS задаёт нужные наборы вручную. ROLLUP заменяет несколько запросов с UNION ALL, это короче и быстрее: таблица читается один раз.
Пример
-- Выручка по регионам и категориям + итог по региону + общий итог
SELECT
COALESCE(region, 'Всего') AS region,
COALESCE(category, 'Итого') AS category,
SUM(amount) AS revenue
FROM sales
GROUP BY ROLLUP (region, category)
ORDER BY GROUPING(region), region, GROUPING(category), category;Связанные термины
COALESCEВозвращает первое не-NULL значение из списка аргументов.GROUP BYГруппирует строки с одинаковыми значениями для применения агрегатных функций.HAVINGФильтрует группы после GROUP BY. В отличие от WHERE, может использовать агрегатные функции.UNION / UNION ALLОбъединяет результаты двух SELECT в один. UNION убирает дубли, UNION ALL оставляет все строки.
Анекдоты по теме
— Что вернёт AVG(salary) если все зарплаты NULL? — NULL. — А SUM? — NULL. — А COUNT(salary)? — 0. COUNT считает непустые, их нет. — А COUNT(*)? — Количество строк. Это COUNT строк, не значений.
Почему GROUP BY не зовут на дни рождения? Потому что он всех складывает в кучу и выдаёт по одному подарку на группу.
— Почему агрегатные функции ненавидят NULL? — Потому что COUNT() их считает, а SUM(колонка) — игнорирует. Двойные стандарты!