grouping()函数用于判断分组上卷产生的null占位,返回1表示小计/总计行,0表示原始值,仅在rollup/cube/grouping sets中有效,不可用于普通group by,且参数须为group by子句中的列。

直接用 GROUPING() 函数判断某列是否因分组上卷而变为空——返回 1 表示是小计/总计行占位,0 表示原始数据值。
GROUPING() 只能在 ROLLUP/CUBE/GROUPING SETS 中用
GROUPING() 不是通用函数,它依赖于分组扩展机制生成的“虚拟空值”。在普通 GROUP BY 里调用会报错:ORA-00937: not a single-group group function。
- 必须搭配
ROLLUP、CUBE或GROUPING SETS使用 - 参数只能是
GROUP BY子句中出现的列(或表达式),不能是计算列或别名 - 单次调用只接受一个参数,如需多列判断,得多次写
GROUPING(col1)、GROUPING(col2)
用 CASE + GROUPING() 把 NULL 占位转成可读标签
原始结果里小计行的 T_DEPT 是 NULL,但数据本身也可能有 NULL,光看值无法区分。这时候靠 GROUPING() 返回的 0/1 做分支:
SELECT CASE GROUPING(t_dept) WHEN 1 THEN '总计' ELSE t_dept END AS dept_label, CASE GROUPING(t_project) WHEN 1 THEN '全部项目' ELSE t_project END AS proj_label, SUM(t_amount) FROM te GROUP BY GROUPING SETS ((t_dept, t_project), t_dept, ()) ORDER BY GROUPING(t_dept), GROUPING(t_project);
-
GROUPING(t_dept) = 1→ 这行是因上卷导致t_dept缺失,不是原始数据为NULL - 注意
ORDER BY里也用了GROUPING(),否则小计/总计可能被挤到中间,破坏报表逻辑顺序
GROUPING_ID() 更适合多维组合判断
当分组维度超过两个(比如 (year, month, region)),逐个写 GROUPING() 很啰嗦,且难看出组合层级。GROUPING_ID() 把所有列的 GROUPING() 结果拼成二进制位向量,再转十进制,一眼识别汇总粒度:
-
GROUPING_ID(year, month, region) = 0→ 全部非空,即明细行(year, month, region) -
= 1→ 二进制001,表示region上卷,对应(year, month)小计 -
= 3→ 二进制011,month和region都上卷,对应year小计 -
= 7→ 二进制111,全上卷,即总计行
这个数字本身没业务含义,但能稳定映射分组结构,比嵌套多个 CASE 更易维护。
真正容易被忽略的是:GROUPING() 的返回值只和当前分组集定义有关,和数据里有没有真实 NULL 完全无关;但很多人会下意识用 NVL(t_dept, '未知') 去“补空”,这反而会把小计行的占位 NULL 也替换成字符串,导致 GROUPING() 判断失效——该用 CASE GROUPING() 的地方,别碰 NVL。











