grouping()仅用于rollup/cube/grouping sets查询中判断聚合占位符,参数必须是group by中实际出现的列名,返回1表示该列被上卷生成的null占位符,0表示明细行,不可用于普通group by或表达式。

GROUPING() 只能用在 ROLLUP/CUBE/GROUPING SETS 查询里
直接在普通 GROUP BY 查询里写 GROUPING(city),SQL Server 会报错:GROUPING() can only be used in a GROUP BY clause with ROLLUP, CUBE or GROUPING SETS。它不是通用判空函数,而是专为聚合占位符设计的“开关信号”。参数必须是 GROUP BY 子句中**实际出现的列名**(不能是表达式、别名或未分组字段),比如 GROUP BY region, city WITH ROLLUP → 可用 GROUPING(region) 和 GROUPING(city),但 GROUPING(UPPER(city)) 会失败。
单列 ROLLUP 时,GROUPING(col) = 1 就是汇总行
对 GROUP BY dept WITH ROLLUP,结果只有两类行:明细行(dept 有值,GROUPING(dept) = 0)和总计行(dept 为 NULL 占位符,GROUPING(dept) = 1)。这时候 GROUPING(dept) 直接告诉你是不是汇总行。常见错误是写 WHERE dept IS NULL 过滤——如果 dept 字段本身允许空值,就会把真实空值和总计行一起干掉。
多列 ROLLUP 必须组合判断 GROUPING() 返回值
对 GROUP BY ROLLUP(dept, team),仅看一个 GROUPING() 不足以区分层级:
-
GROUPING(dept) = 0 AND GROUPING(team) = 0→ 明细行(dept和team都是原始值) -
GROUPING(dept) = 0 AND GROUPING(team) = 1→dept小计(team被上卷,占位NULL) -
GROUPING(dept) = 1 AND GROUPING(team) = 1→ 全表总计(两列都被上卷)
注意:顺序不能反,GROUPING(dept, team) 是非法写法 —— GROUPING() 每次只接受一个列名;想用单个整数编码所有组合,得用 GROUPING_ID(dept, team)(但 SQL Server 仅支持在 GROUPING SETS 中使用,WITH ROLLUP 下不可用)。
用 CASE + GROUPING() 替换 NULL 显示更安全
直接 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() 实现,没有替代方案。











