ROLLUP需配合GROUP BY使用,按列从左到右生成分层汇总,NULL标识汇总行,须用GROUPING()函数区分真实NULL与汇总占位符,避免误判。

ROLLUP 能生成分层小计和总计,但必须配合 GROUP BY 使用,且 NULL 值代表汇总行——这是理解结果的关键。
ROLLUP 的分组顺序决定小计层级
SQL Server 按 GROUP BY 中列的**从左到右顺序**构建分组树。比如 GROUP BY a, b, c WITH ROLLUP 会生成:(a,b,c)、(a,b,NULL)、(a,NULL,NULL)、(NULL,NULL,NULL) 四级汇总。
- 最细粒度是完整组合(如部门+员工+月份)
- 中间层级小计对应左侧字段固定、右侧为
NULL(如部门固定、员工为NULL表示该部门总和) - 最顶层
(NULL,NULL,NULL)是全表总计 - 如果把列序换成
GROUP BY c, b, a WITH ROLLUP,小计逻辑就变成按月份优先聚合,结果完全不同
区分真实 NULL 和 ROLLUP 生成的 NULL
ROLLUP 用 NULL 标记汇总行,但这和原始数据里的 NULL 冲突。直接 WHERE col IS NULL 会混入脏数据。
- 用
GROUPING()函数判断:例如GROUPING(dept_name) = 1表示该行dept_name是 ROLLUP 自动生成的汇总占位符 - 常用写法:
CASE WHEN GROUPING(dept_name) = 1 THEN '部门小计' ELSE dept_name END - 多个字段时,
GROUPING()对每个字段单独返回 0 或 1,可组合判断层级(如GROUPING(a)=1 AND GROUPING(b)=0表示 a 汇总、b 仍有效)
ROLLUP 和 GROUPING SETS 的性能与灵活性差异
WITH ROLLUP 是语法糖,底层等价于特定 GROUPING SETS。但手动写 GROUPING SETS 更灵活,也更容易控制哪些组合需要小计。
-
GROUP BY a,b WITH ROLLUP≡GROUP BY GROUPING SETS ((a,b), (a), ()) - 如果只需要部门小计和总计,不要“部门+员工”明细小计,
ROLLUP做不到,必须用GROUPING SETS ((a,b), (a), ())显式声明 - 复杂报表中,
GROUPING SETS执行计划通常更稳定,ROLLUP在大数据量下可能因隐式多层分组触发额外排序
真正难的是在多维交叉汇总里准确识别哪一行是哪一级小计——别只盯着 NULL 看,务必结合 GROUPING() 的返回值做判断,否则导出到 Excel 后小计位置错乱很难排查。

















