grouping()函数专用于rollup/cube/grouping sets场景,返回0(列参与分组)或1(列未参与、为汇总生成的null),是唯一能区分真实null与汇总null的工具,普通group by中使用无意义。

GROUPING() 函数只在 GROUP BY + ROLLUP/CUBE/GROUPING SETS 场景下有意义
单独写 GROUPING(column) 不会报错,但永远返回 0 —— 它不是普通标量函数,而是专为识别「由汇总操作(如 ROLLUP)自动生成的 NULL 值」而设计的。真正的 NULL 和汇总产生的 NULL 在结果里长得一样,GROUPING() 是唯一能区分它们的工具。
常见错误是把它用在普通 GROUP BY column 里,比如:
SELECT dept, COUNT(*), GROUPING(dept) FROM emp GROUP BY dept;
这里 GROUPING(dept) 全是 0,毫无意义。它必须配合扩展分组语法才起作用。
ROLLUP 中如何用 GROUPING() 标记层级汇总行
ROLLUP 会按顺序生成多级小计和总计行,这些行对应字段值为 NULL,但你需要知道哪一行是「部门小计」、哪一行是「公司总计」。这时靠 GROUPING() 返回 1/0 判断该列是否参与了当前行的分组。
例如:
SELECT CASE WHEN GROUPING(dept) = 1 THEN 'ALL_DEPTS' ELSE dept END AS dept, CASE WHEN GROUPING(role) = 1 THEN 'ALL_ROLES' ELSE role END AS role, COUNT(*) AS cnt FROM emp GROUP BY dept, role WITH ROLLUP;
关键点:
-
GROUPING(dept) = 1表示这一行不是按 dept 分的,而是 dept 维度被“卷起”了(即更高层汇总) - 当
dept和role都为 NULL 时,GROUPING(dept) = 1 AND GROUPING(role) = 1,说明这是最终总计行 - 顺序很重要:
GROUP BY a, b WITH ROLLUP会产生 (a,b)、(a,NULL)、(NULL,NULL) 三类行,GROUPING()的组合值就是你的判断依据
GROUPING() 返回值不是布尔,别直接当条件用
GROUPING() 返回的是 TINYINT(MySQL/SQL Server)或 INTEGER(PostgreSQL),值只有 0 或 1。很多人写 WHERE GROUPING(dept) 以为等价于 = 1,但某些数据库(如 PostgreSQL)会报错:「cannot use grouping in WHERE without GROUP BY extension」。
正确做法:
- 过滤汇总行:用
HAVING GROUPING(dept) = 1(HAVING 可用,WHERE 不行) - 在 SELECT 或 ORDER BY 中安全使用
GROUPING() - 避免写
IF(GROUPING(dept), ...)这类隐式转换,显式写GROUPING(dept) = 1
不同数据库对 GROUPING() 的支持差异
不是所有 SQL 引擎都支持 GROUPING()。MySQL 8.0+、PostgreSQL 9.5+、SQL Server 全支持;SQLite 不支持;老版本 MySQL(
替代方案有限:
- 用
COUNT(*) OVER (PARTITION BY dept)等窗口函数模拟部分逻辑(但无法真正区分汇总 NULL) - 应用层加标记:先查出原始分组结果,再用代码补全小计行并打标
- 确认执行计划:某些数据库在启用
ROLLUP时即使没写GROUPING(),也会在元数据中标记汇总行,但不可靠
最稳妥的方式,是先查 SELECT VERSION() 或文档,再决定是否依赖 GROUPING() —— 它看起来简单,但一旦跨库迁移,容易卡在兼容性上。










