ROLLUP生成N+1个层级分组,按列顺序从右到左逐级撤出形成树状父子关系;CUBE穷举2^N种组合,不依赖顺序且含大量业务无意义分组;GROUPING()函数是唯一可靠方式区分汇总占位符NULL与真实NULL值。

因为 CUBE 和 ROLLUP 对 GROUP BY 列的组合逻辑完全不同:ROLLUP 按列顺序走一条“主干路径”做层级归并,CUBE 则穷举所有 2N 种列组合。
ROLLUP 只生成 N+1 个分组,且严格依赖列顺序
ROLLUP 不是“把前面的列加总”,而是从左到右逐级撤出最右侧分组列,形成树状父-子关系。比如 GROUP BY dept, team, emp WITH ROLLUP 产出:
-
(dept, team, emp)—— 员工明细 -
(dept, team, NULL)—— 小组小计 -
(dept, NULL, NULL)—— 部门小计 -
(NULL, NULL, NULL)—— 全局总计
它不会生成 (NULL, team, emp) 或 (NULL, team, NULL) 这类跨级组合——这些在业务上无法构成合法的“上级→下级”关系。一旦写反顺序,比如 GROUP BY emp, team, dept,就只剩员工级、空团队、空部门三层,小组维度直接消失。
CUBE 生成全部 2N 种组合,不关心业务层级
CUBE 把每个分组列都当作独立维度,暴力枚举所有开/关状态。对同样三列 dept, team, emp,WITH CUBE 会产出 8 行,包括:
(dept, team, emp)-
(dept, team, NULL)—— 小组小计 -
(dept, NULL, emp)—— “某部门下所有小组里的同名员工”(通常无意义) -
(dept, NULL, NULL)—— 部门小计 -
(NULL, team, emp)—— “全公司某小组同名员工”(也常无意义) -
(NULL, team, NULL)—— 小组全局小计 -
(NULL, NULL, emp)—— 员工全局小计 -
(NULL, NULL, NULL)—— 总计
这意味着:加一个字段,分组数翻倍。5 个字段就是 32 组,查询耗时和结果集体积可能指数增长,尤其当某些组合在业务上根本不存在解释口径时。
GROUPING() 是唯一可靠方式区分 NULL 是占位符还是真数据
ROLLUP/CUBE 输出的 NULL 是占位符,不代表原始数据里真有 NULL 值。如果表中 region 字段本身允许为空,仅靠 IS NULL 无法判断这行是“华东区小计”还是“地区未知的明细”。必须用 GROUPING(region):
- 返回
1→ 该NULL是汇总行占位符 - 返回
0→ 该NULL来自原始数据
MySQL 8.0+ 和 SQL Server 支持,PostgreSQL 需用 GROUPING SETS 模拟;但无论哪种,漏掉 GROUPING() 就等于把汇总行和脏数据混在一起处理——这是上线后报表数值对不上最常见根源之一。

















