在SQL数据统计需求中,我们常常需要在获取各分组明细数据的同时,得到对应分组的小计以及所有数据的整体总计,传统的GROUP BY语句仅支持单一分组维度的统计,无法直接输出多层级汇总结果。使用GROUPING SETS语法可以手动指定多个分组组合,一次性返回不同维度的统计结果,高效实现总计与小计的计算。

GROUPING SETS基本语法
GROUPING SETS属于GROUP BY的扩展语法,允许在一个GROUP BY子句中指定多个分组组合,每个分组组合对应一组统计结果。基本语法格式如下:
SELECT
分组列1,
分组列2,
聚合函数(统计列) AS 统计结果
FROM 表名
GROUP BY GROUPING SETS (
(分组列1, 分组列2), -- 组合1:按两列分组,对应明细数据
(分组列1), -- 组合2:仅按第一列分组,对应第一列的小计
() -- 组合3:空分组,对应整体总计
)
实际示例演示
假设我们有一张销售记录表sales,表结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| region | VARCHAR | 销售区域 |
| product | VARCHAR | 产品名称 |
| amount | INT | 销售金额 |
现在需要统计每个区域下每个产品的销售金额,同时统计每个区域的总销售金额,以及所有区域的总销售金额,使用GROUPING SETS实现的SQL如下:
SELECT
region,
product,
SUM(amount) AS total_amount
FROM sales
GROUP BY GROUPING SETS (
(region, product), -- 按区域和产品分组,得到明细数据
(region), -- 按区域分组,得到每个区域的小计
() -- 空分组,得到所有数据的总计
)
ORDER BY region, product;
执行上述语句后,结果会包含三类数据:
- region和product都有值:对应某个区域下某个产品的销售明细
- region有值、product为NULL:对应该区域所有产品的销售小计
- region和product都为NULL:对应所有区域所有产品的总计
区分分组层级的GROUPING函数
当结果中出现NULL值时,无法直接区分是原始数据中的NULL还是分组汇总产生的NULL,此时可以使用GROUPING函数判断。GROUPING函数接收一个列名作为参数,返回1表示该列在当前分组组合中未被分组(即该列值为汇总产生的NULL),返回0表示该列参与了当前分组。
结合GROUPING函数优化上述查询,添加分组层级标识:
SELECT
region,
product,
SUM(amount) AS total_amount,
-- 判断分组层级:0表示明细,1表示区域小计,2表示总计
CASE
WHEN GROUPING(region) = 1 AND GROUPING(product) = 1 THEN 2
WHEN GROUPING(region) = 0 AND GROUPING(product) = 1 THEN 1
ELSE 0
END AS group_level
FROM sales
GROUP BY GROUPING SETS (
(region, product),
(region),
()
)
ORDER BY region, product;
注意事项
使用GROUPING SETS时需要注意以下几点:
- GROUPING SETS中指定的列必须是SELECT子句中出现的非聚合列
- 空分组
()表示不按任何列分组,对应整体总计 - 不同数据库对GROUPING SETS的支持程度略有差异,主流关系型数据库如MySQL 8.0+、PostgreSQL、SQL Server、Oracle都支持该语法
- 如果不需要手动指定所有分组组合,也可以使用ROLLUP或CUBE语法,前者生成层级式分组组合,后者生成所有可能的分组组合,而GROUPING SETS可以灵活指定需要的分组组合,更贴合自定义需求
GROUPING SETS的核心价值是减少多次查询带来的性能开销,通过一次查询返回所有需要的统计维度结果,在报表类数据统计场景中应用非常广泛。
SQLGROUPING_SETS分组统计总计小计修改时间:2026-07-17 17:39:25