rollup和cube是oracle中group by的汇总扩展语法,非函数;rollup按层级递减生成小计(如rollup(a,b,c)对应(a,b,c)→(a,b)→(a)→()),cube穷举所有维度组合(如cube(a,b,c)产生8种分组);二者均需配合grouping()或grouping_id()区分占位null与真实null,避免误删或漏行;使用时须注意字段顺序、性能影响及表达式一致性。

ROLLUP 和 CUBE 不是函数,是 Oracle 中嵌入 GROUP BY 的汇总扩展语法。直接写 GROUP BY ROLLUP(...) 就能生成小计、合计行,但必须配合 GROUPING() 或 GROUPING_ID() 才能安全识别哪些 NULL 是占位符——否则极易误删真实数据或漏掉汇总行。
ROLLUP 生成层级递减小计,顺序决定汇总逻辑
ROLLUP(a, b, c) 实际执行四层分组:(a,b,c) → (a,b) → (a) → ()(全表)。它从右往左“剥洋葱”,右边字段最先被忽略。
常见错误现象:GROUP BY ROLLUP(deptno, job) 和 GROUP BY ROLLUP(job, deptno) 输出结构完全不同——前者先按部门再职位,小计只出现在部门级;后者先按职位再部门,小计出现在职位级。
使用场景:需要按业务层级做自然汇总,比如“部门→岗位→员工”这种有明确父子关系的维度链。
实操建议:
- 用
GROUPING_ID(deptno, job)控制排序:值越小越底层(0=明细,1=deptno 小计,3=总计) - 别直接
ORDER BY deptno, job,否则汇总行可能插在明细中间 - NULL 是占位符,不是缺失值;原始数据中
deptno IS NULL AND job IS NOT NULL根本不可能存在
CUBE 穷举所有组合,行数爆炸需警惕
CUBE(a, b, c) 等价于对全部 2³ = 8 种非空子集分别 GROUP BY:即 (a,b,c)、(a,b)、(a,c)、(b,c)、(a)、(b)、(c)、()。
性能影响明显:3 列最多输出 8 倍明细行数;4 列就是 16 倍——数据量稍大就拖慢查询。
常见错误现象:看到结果里一堆 a=NULL, b=10, c=NULL 就懵了,不知道这行到底代表什么维度的统计。
实操建议:
- 用
GROUPING(a) + GROUPING(b) + GROUPING(c)联合判断归属(例如只有 b=1 表示仅按 b 分组) - 如果只要某几个特定组合(如只想要部门小计 + 职位小计,不要交叉项),改用
UNION ALL拼接多个GROUP BY更可控 - 别盲目套用
CUBE,尤其在宽表或大数据量场景下
必须用 GROUPING() 区分真实 NULL 和汇总占位 NULL
原始数据里的 NULL 和 ROLLUP/CUBE 自动生成的占位 NULL 在结果里完全无法肉眼分辨。
常见错误:写 WHERE deptno IS NULL 想过滤出“部门合计行”,结果既删掉了真实 deptno 为 NULL 的记录,又漏掉了 deptno 占位但 job 不为空的那类小计行。
实操建议:
-
GROUPING(deptno)返回 1 表示该行 deptno 是汇总占位,返回 0 表示来自实际数据 - 常用写法:
CASE WHEN GROUPING(deptno) = 1 THEN '总计' ELSE TO_CHAR(deptno) END AS dept_label - 绝对不要在
WHERE子句中直接判断字段是否为NULL来筛选汇总行
ROLLUP 和 CUBE 性能与可读性权衡
ROLLUP 和 CUBE 都是语法糖,不依赖额外函数调用,但它们让 SQL 变得隐式且难调试。
容易被忽略的地方:当分组字段含表达式(如 TRUNC(hiredate, 'MM'))或别名时,GROUPING() 参数必须与 GROUP BY 中的原始表达式完全一致,不能用别名。
实操建议:
- 复杂需求优先考虑
GROUPING SETS,它显式列出所有要汇总的维度组合,语义更清晰 - 上线前务必在生产数据量级上压测,特别是
CUBE在 4 维以上时响应时间可能陡增 - 报表类 SQL 中若需固定展示“小计/合计”标签,
GROUPING_ID()比嵌套多个GROUPING()更简洁











