核心概念
GROUPING SETS 允许你在一个单独的 GROUP BY 查询中,显式定义多个不同的分组条件。数据库会为每一个指定的分组集分别计算聚合,
然后将所有结果联合(UNION ALL)在一起返回。
它的最大优势是灵活性和效率。你不需要写多个复杂的 UNION ALL 查询,数据库引擎可以更高效地在一个单一通道中完成所有分组聚合。
语法
sql
SELECT
column1,
column2,
...,
aggregate_function(column)
FROM table_name
GROUP BY GROUPING SETS (
(column1, column2), -- 分组集 1
(column1), -- 分组集 2
(column2), -- 分组集 3
() -- 分组集 4 (总计)
);
示例详解
我们继续使用熟悉的 sales 表:
year country category sales
2023 USA Electronics 1000
2023 USA Clothing 200
2023 China Electronics 800
2023 China Clothing 150
2024 USA Electronics 1200
2024 USA Clothing 250
2024 China Electronics 950
2024 China Clothing 180
示例 1:自定义分组集
假设业务方只需要以下三种汇总报告:
按 (year, country) 分组的总销售额
按 (category) 分组的总销售额
所有数据的总计 ()
用 UNION ALL 会非常冗长,而用 GROUPING SETS 则非常简洁。
sql
SELECT
COALESCE(CAST(year AS STRING), 'All Years') AS year,
COALESCE(country, 'All Countries') AS country,
COALESCE(category, 'All Categories') AS category,
SUM(sales) AS total_sales
FROM sales
GROUP BY GROUPING SETS (
(year, country), -- 分组集 1: 按年和国家
(category), -- 分组集 2: 按类别
() -- 分组集 3: 总计
)
ORDER BY year, country, category;
结果与解释:
year country category total_sales 说明
2023 China All Categories 950 分组集1:2023年中国的总计
2023 USA All Categories 1200 分组集1:2023年美国的总计
2024 China All Categories 1130 分组集1:2024年中国的总计
2024 USA All Categories 1450 分组集1:2024年美国的总计
All Years All Countries Clothing 780 分组集2:所有年份所有国家的服装总计
All Years All Countries Electronics 3950 分组集2:所有年份所有国家的电子产品总计
All Years All Countries All Categories 4730 分组集3:所有数据的总计关键点:
我们只得到了我们明确要求的三种分组聚合结果,没有 CUBE 或 ROLLUP 产生的额外组合。
这比写三个独立的 SELECT ... GROUP BY ... 然后用 UNION ALL 连接起来要高效得多,而且代码更清晰。
示例 2:实现与 ROLLUP 和 CUBE 等价的效果
GROUPING SETS 是基础,ROLLUP 和 CUBE 只是它的语法糖。
等价于 ROLLUP(year, country):
ROLLUP(a, b) 等价于 GROUPING SETS( (a, b), (a), () )
sql
-- 这两种写法结果相同
GROUP BY ROLLUP (year, country)
GROUP BY GROUPING SETS ( (year, country), (year), () )
等价于 CUBE(year, country):
CUBE(a, b) 等价于 GROUPING SETS( (a, b), (a), (b), () )
sql
-- 这两种写法结果相同
GROUP BY CUBE (year, country)
GROUP BY GROUPING SETS ( (year, country), (year), (country), () )
示例 3:混合分组集(高级用法)
这是 GROUPING SETS 真正强大的地方,你可以创建 ROLLUP 和 CUBE 无法直接生成的、不对称的分组组合。
假设你需要:
按 (year, country) 的明细和小计(即 ROLLUP(year, country))
同时,再额外加上按 (category) 的小计。
sql
SELECT
COALESCE(CAST(year AS STRING), 'All Years') AS year,
COALESCE(country, 'All Countries') AS country,
COALESCE(category, 'All Categories') AS category,
SUM(sales) AS total_sales,
GROUPING_ID(year, country, category) AS grouping_id
FROM sales
GROUP BY GROUPING SETS (
ROLLUP (year, country), -- 分组集 1: 一个完整的ROLLUP
(category) -- 分组集 2: 一个单独的分组
)
ORDER BY grouping_id, year, country, category;
结果(部分):
你会得到:
ROLLUP(year, country) 产生的所有行(细粒度数据、年度-国家小计、年度小计、总计)。
再加上 GROUP BY category 产生的行(按产品类别的小计)。
这种不对称的聚合需求只能用 GROUPING SETS 来实现。
使用 GROUPING() 和 GROUPING_ID() 进行标识
和 ROLLUP/CUBE 一样,GROUPING SETS 也需要 GROUPING_ID() 来帮助识别每一行属于哪个分组集。
sql
SELECT
year,
country,
category,
SUM(sales) AS total_sales,
GROUPING(year) AS g_year,
GROUPING(country) AS g_country,
GROUPING(category) AS g_category,
GROUPING_ID(year, country, category) AS grouping_id
FROM sales
GROUP BY GROUPING SETS (
(year, country),
(category),
()
);
总结与用途
特性 说明
核心优势 极致的灵活性。可以精确指定任何你想要的分组组合,包括不对称的、不完整的层次结构。
性能 在大多数数据库实现中,比编写等效的多个 UNION ALL 查询性能更高。
与ROLLUP/CUBE关系 ROLLUP 和 CUBE 是预定义特定模式的 GROUPING SETS 的快捷方式。
最佳搭档 GROUPING_ID() 函数,用于在复杂的混合分组集中精确识别每一行的聚合级别。
适用场景 1. 只需要特定分组组合的报表,避免 CUBE 产生过多无用数据。
2. 创建不对称的、自定义的汇总报告。
3. 优化现有的使用 UNION ALL 的复杂聚合查询。
一句话总结:
当你需要完全的控制权,只想聚合你明确指定的维度组合时,GROUPING SETS 是你的最佳选择。它是 SQL 分组聚合功能中的"瑞士军刀",强大而精准。
Grouping SETS 函数的使用
最新推荐文章于 2025-12-04 22:03:39 发布
957

被折叠的 条评论
为什么被折叠?



