grouping()仅在rollup/cube/grouping sets中有效,返回0/1标识汇总行;不可用于普通group by,不支持表达式参数;需结合case和having精确区分占位null与真实null。

GROUPING() 不是通用空值判断函数,只在 ROLLUP/CUBE/GROUPING SETS 查询里有效;用错地方会直接报错。
GROUPING() 只能用在带 ROLLUP、CUBE 或 GROUPING SETS 的查询中
SQL Server 和 MySQL 8.0+ 都要求 GROUPING() 必须配合聚合扩展子句使用。普通 GROUP BY 里写 GROUPING(city),SQL Server 会明确报错:GROUPING() can only be used in a GROUP BY clause with ROLLUP, CUBE or GROUPING SETS。MySQL 8.0 虽支持该函数,但同样拒绝在纯 GROUP BY 中调用。
- 合法:
GROUP BY region, city WITH ROLLUP→ 可用GROUPING(region)和GROUPING(city) - 非法:
GROUP BY region, city→GROUPING(region)语法错误 - 注意:不能传表达式,比如
GROUPING(UPPER(city))或GROUPING(COALESCE(city, '未知'))都会失败
单列 ROLLUP 时,GROUPING(col) = 1 就是汇总行
对 GROUP BY dept WITH ROLLUP,结果只有两类行:明细行(dept 有值,GROUPING(dept) = 0)和总计行(dept 为 NULL 占位符,GROUPING(dept) = 1)。这时候它就是个“开关”。
- 别用
WHERE dept IS NULL过滤总计行 —— 如果dept字段本身允许 NULL,就会误删真实空值数据 - 正确做法是
HAVING GROUPING(dept) = 1,或在SELECT中用CASE WHEN GROUPING(dept) = 1 THEN '总计' ELSE dept END -
GROUPING()返回tinyint(SQL Server)或unsigned int(MySQL),不是布尔值,但逻辑上只取 0/1
多列 ROLLUP 必须组合判断 GROUPING() 值
对 GROUP BY ROLLUP(dept, team),仅看一个 GROUPING() 无法区分层级。必须用两个值的组合来判断:
-
GROUPING(dept) = 0 AND GROUPING(team) = 0→ 明细行(原始数据) -
GROUPING(dept) = 0 AND GROUPING(team) = 1→ dept 小计(team 被上卷,占位 NULL) -
GROUPING(dept) = 1 AND GROUPING(team) = 1→ 全表总计(两列都被上卷) - 顺序不能反:
GROUPING(dept, team)是非法写法 ——GROUPING()每次只接受一个列名
用 CASE + GROUPING() 替换 NULL,而不是 COALESCE
直接 COALESCE(team, '小计') 会把所有 team IS NULL 的行(包括真实空值和所有汇总层级)都打上“小计”,污染语义。必须绑定 GROUPING() 判断。
SELECT
CASE
WHEN GROUPING(dept) = 1 THEN '总计'
WHEN GROUPING(team) = 1 THEN dept + ' 小计'
ELSE dept
END AS dept_label,
CASE WHEN GROUPING(team) = 1 THEN NULL ELSE team END AS team,
COUNT(*) AS cnt
FROM staff
GROUP BY dept, team WITH ROLLUP;
关键点在于:汇总行里的 NULL 是占位符,业务字段本身的 NULL 仍需保留原义 —— 这种区分只能靠 GROUPING() 实现,没有替代方案。










