При проведении аналитики часто требуется посмотреть на статистические показатели в разных разрезах. Например, для анализа средней зарплаты интересно посмотреть на среднюю зарплату по каждому подразделению и по всей организации в целом. Для решения этой задачи SQL поддерживает наборы группирования, реализованные через ROLLUP, CUBE, GROUPING SETS.

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

Конструкция ROLLUP в цикле выполняет группировку по подспискам переданного списка выражений, на каждой итерации убирая по одному выражению с конца списка, включая пустой список (вычисление агрегатных функций по всем строкам).

Например, для GROUP BY ROLLUP (выражение1, выражение2, выражение3) результатом запроса будет объединение результатов GROUP BY по

  • выражение1, выражение2, выражение3;
  • выражение1, выражение2;
  • выражение1;
  • все строки выборки.

Синтаксис ROLLUP:

GROUP BY ROLLUP (выражение1, выражение2, ... , выражениеN)

Рассмотрим пример. Получим минимальную и максимальную цены на товары в городах с идентификаторами 2 и 3 в следующих разрезах:

  • по каждой категории товаров в городе;
  • по всем магазинам города;
  • по всем категориям товаров всех городов.

Для начала выведем исходные данные:

SELECT sa.city_id, 
       p.category_id,
       pp.price
  FROM product_price pp
  JOIN product p
    ON p.product_id = pp.product_id
  JOIN store_address sa
    ON sa.store_id = pp.store_id
 WHERE sa.city_id IN (2, 3)
 ORDER BY sa.city_id,
          p.category_id,
          pp.price
city_id category_id price
1 2 6 21500.00
2 2 6 22900.00
3 2 6 23500.00
4 2 7 17800.00
5 3 3 10500.00

Воспользуемся ROLLUP:

SELECT sa.city_id, 
       p.category_id,
       min(pp.price) AS price_min,
       max(pp.price) AS price_max
  FROM product_price pp
  JOIN product p
    ON p.product_id = pp.product_id
  JOIN store_address sa
    ON sa.store_id = pp.store_id
 WHERE sa.city_id IN (2, 3)
 GROUP BY ROLLUP (sa.city_id, p.category_id)
 ORDER BY sa.city_id NULLS LAST, 
          p.category_id NULLS LAST
city_id category_id price_min price_max
1 2 6 21500.00 23500.00
2 2 7 17800.00 17800.00
3 2 NULL 17800.00 23500.00
4 3 3 10500.00 10500.00
5 3 NULL 10500.00 10500.00
6 NULL NULL 10500.00 23500.00

Обрати внимание, что значения полей из GROUP BY, по которым не производилась группировка, равны NULL. Таким образом, результаты группировки по sa.city_id и p.category_id представлены в строках 1, 2 и 4. Результаты группировки по sa.city_id представлены в строках 3 и 5. Строка 6 является вычислением агрегатных функций по всему набору данных.

4.10 HAVING

4.12 CUBE