Grouping SETS 函数的使用

核心概念
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 分组聚合功能中的"瑞士军刀",强大而精准。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值