grouping函数返回0或1:返回0表示该列值来自原始数据分组,返回1表示该列是rollup/cube/grouping sets生成的汇总占位符(即系统填充的null),专用于区分语义不同的null。

GROUPING 函数返回什么值?
GROUPING 是一个专用于 GROUP BY + ROLLUP/CUBE/GROUPING SETS 场景的函数,它只接收一个列名作为参数,返回 0 或 1:
- 返回
0:该行中该列是真实数据(有具体值)
- 返回
1:该行中该列是小计/总计产生的空值(即由ROLLUP等自动补的NULL)
关键点在于:它不判断值本身是不是NULL,而是判断这个NULL是原始数据里的,还是聚合机制“造出来”的。
常见错误是直接用 IS NULL 判断——原始数据里真有 NULL 的话,就会和小计行混淆。而 GROUPING(col) 能准确区分这两类 NULL。
怎么在 ROLLUP 查询里用 GROUPING 标记层级?
当你写 GROUP BY a, b WITH ROLLUP,会生成多级汇总行((a,b)、(a,NULL)、(NULL,NULL)),但所有 NULL 看起来一样。用 GROUPING 就能给每级打标签:
SELECT
CASE
WHEN GROUPING(dept) = 1 AND GROUPING(role) = 1 THEN '总计'
WHEN GROUPING(dept) = 0 AND GROUPING(role) = 1 THEN '部门小计:' || dept
ELSE role
END AS label,
COUNT(*) AS cnt
FROM staff
GROUP BY dept, role WITH ROLLUP;
注意:
-
GROUPING(dept) = 1表示当前行不是按dept分组的(即该层被折叠) - 多列组合判断时,顺序必须和
GROUP BY子句一致 - 不同数据库对字符串拼接符号支持不同(PostgreSQL/Oracle 用
||,MySQL 用CONCAT())
GROUPING 和 GROUPING_ID 有什么区别?
GROUPING 每次只能查一列,而 GROUPING_ID(col1, col2, col3) 把多个 GROUPING(col) 结果当二进制位拼起来,返回一个整数编码。比如三列都为 1(即全小计行)时,GROUPING_ID(a,b,c) = 7(二进制 111)。
实用场景是简化多维判断:
- 想快速过滤出“仅按 a 小计、b 和 c 展开”的行?查
GROUPING_ID(a,b,c) = 4(即100) - 想排除所有小计行,只留明细?加条件
GROUPING_ID(a,b,c) = 0 - MySQL 8.0+ 和 SQL Server 支持;PostgreSQL 目前不支持
GROUPING_ID,得手写CASE组合
容易忽略的兼容性与陷阱
GROUPING 不是标准 SQL 的必需功能,但主流数据库(PostgreSQL 9.5+、SQL Server、Oracle、MySQL 8.0+、Trino、StarRocks)都支持。不过有几点必须注意:
- 如果 GROUP BY 用了别名(如 GROUP BY region AS r),GROUPING(r) 会报错——必须用原始列名或表达式,不能用别名
- 在窗口函数中不能用 GROUPING,它只在聚合上下文有效
- 当你用 COALESCE(dept, '全部') 替换小计行的 NULL 后,GROUPING(dept) 仍返回 1,不受 COALESCE 影响——这点很关键,别误以为替换后就“不是小计了”
- 某些 BI 工具(如旧版 Tableau)在解析含 GROUPING 的查询时可能报语法错误,建议先在数据库客户端验证
真正麻烦的不是写法,而是意识到:只要用了 ROLLUP 或 CUBE,就必须靠 GROUPING 来语义化那些 NULL 行,否则前端展示时根本分不清哪行是数据缺失、哪行是逻辑汇总。










