В этом руководстве вы узнаете, как использовать SQL Server GROUPING SETS для создания нескольких группировочных наборов.
Настройте сводную таблицу продаж
Давайте создадим новую таблицу с именем sales.sales_summary для демонстрации.
SELECT b.brand_name AS brand, c.category_name AS category, p.model_year, round( SUM( quantity * i.list_price *(1 - discount) ), 0 ) sales INTO sales.sales_summary FROM sales.order_items i INNER JOIN production.products p ON p.product_id = i.product_id INNER JOIN production.brands b ON b.brand_id = p.brand_id INNER JOIN production.categories c ON c.category_id = p.category_id GROUP BY b.brand_name, c.category_name, p.model_year ORDER BY b.brand_name, c.category_name, p.model_year;
В этом запросе мы извлекаем данные об объеме продаж по брендам и категориям и заполняем ими таблицу sales.sales_summary.
Следующий запрос возвращает данные из таблицы sales.sales_summary:
SELECT * FROM sales.sales_summary ORDER BY brand, category, model_year;
Начало работы с SQL Server GROUPING SETS
По определению, набор группировки — это группа столбцов, по которым вы группируете. Обычно один запрос с агрегатом определяет один набор группировки.
Например, следующий запрос определяет набор группировки, включающий бренд и категорию, которая обозначается как(бренд, категория). Запрос возвращает объем продаж, сгруппированный по бренду и категории:
SELECT brand, category, SUM(sales) sales FROM sales.sales_summary GROUP BY brand, category ORDER BY brand, category;
Следующий запрос возвращает объем продаж по бренду. Он определяет набор группировки(бренд):
SELECT brand, SUM(sales) sales FROM sales.sales_summary GROUP BY brand ORDER BY brand;
Следующий запрос возвращает сумму продаж по категориям. Он определяет набор группировки(категорию):
SELECT category, SUM(sales) sales FROM sales.sales_summary GROUP BY category ORDER BY category;
Следующий запрос определяет пустой набор группировки(). Он возвращает объем продаж по всем брендам и категориям.
SELECT SUM(sales) sales FROM sales.sales_summary;
Четыре запроса выше возвращают четыре набора результатов с четырьмя наборами группировки:
(brand, category) (brand) (category) ()
Чтобы получить единый набор результатов с агрегированными данными по всем группирующим наборам, можно использовать оператор UNION ALL.
Поскольку оператор UNION ALL требует, чтобы все результирующие наборы имели одинаковое количество столбцов, необходимо добавить NULL в список выбора запросов следующим образом:
SELECT brand, category, SUM(sales) sales FROM sales.sales_summary GROUP BY brand, category UNION ALL SELECT brand, NULL, SUM(sales) sales FROM sales.sales_summary GROUP BY brand UNION ALL SELECT NULL, category, SUM(sales) sales FROM sales.sales_summary GROUP BY category UNION ALL SELECT NULL, NULL, SUM(sales) FROM sales.sales_summary ORDER BY brand, category;
Запрос сгенерировал один результат с агрегатами для всех группировочных наборов, как мы и ожидали.
Однако у него есть две основные проблемы:
- Запрос довольно длинный.
- Запрос выполняется медленно, поскольку SQL Server необходимо выполнить четыре подзапроса и объединить результирующие наборы в один.
Для устранения этих проблем SQL Server предоставляет подпункт предложения GROUP BY, который называется GROUPING SETS.
GROUPING SETS определяет несколько группирующих наборов в одном запросе. Ниже показан общий синтаксис GROUPING SETS:
SELECT column1, column2, aggregate_function(column3) FROM table_name GROUP BY GROUPING SETS( (column1, column2), (column1), (column2), () );
Этот запрос создает четыре группировочных набора:
(column1,column2) (column1) (column2) ()
Вы можете использовать эти GROUPING SETS, чтобы переписать запрос, который получает данные о продажах, следующим образом:
SELECT brand, category, SUM(sales) sales FROM sales.sales_summary GROUP BY GROUPING SETS( (brand, category), (brand), (category), () ) ORDER BY brand, category;
Как видите, запрос выдает тот же результат, что и запрос, использующий оператор UNION ALL. Однако этот запрос гораздо более читабелен и, конечно, более эффективен.
Функция ГРУППИРОВКИ
Функция GROUPING указывает, агрегирован ли указанный столбец в предложении GROUP BY или нет. Она возвращает 1 для агрегированного или 0 для неагрегированного в наборе результатов.
См. следующий пример запроса:
SELECT GROUPING(brand) grouping_brand, GROUPING(category) grouping_category, brand, category, SUM(sales) sales FROM sales.sales_summary GROUP BY GROUPING SETS( (brand, category), (brand), (category), () ) ORDER BY brand, category;
Значение в столбце grouping_brand указывает, агрегирована ли строка или нет:
- 1 означает, что объем продаж суммируется по брендам
- 0 означает, что объем продаж не агрегируется по брендам.
Та же логика применяется к столбцу grouping_category.
Краткое содержание
- Используйте GROUPING SETS для создания нескольких группировочных наборов в запросе.