GROUPING函数在ROLLUP/CUBE中返回1表示该列NULL由汇总生成,返回0表示NULL来自原始数据;它仅在含ROLLUP、CUBE或GROUPING SETS的GROUP BY中有效,用于精准区分占位NULL与真实NULL。

GROUPING函数返回值的含义必须结合GROUP BY ROLLUP/CUBE理解
单独写 GROUPING(col) 没有意义,它只在含汇总层级的分组(如 GROUP BY ROLLUP(a, b))中才有明确语义:当某列值为 NULL 是因汇总产生(比如小计行),GROUPING(col) 返回 1;若该 NULL 是原始数据真实值,则返回 0。这是唯一能可靠区分“汇总产生的 NULL”和“数据本身的 NULL”的方式。
常见错误是直接对普通 GROUP BY a, b 使用 GROUPING(),此时所有结果行该函数都返回 0,起不到区分作用。
用CASE WHEN + GROUPING判断小计行并打标签
典型场景是生成带小计的报表,需把小计行标记为“小计”、明细行保留原值。关键点在于:必须对每个参与 ROLLUP 的列单独调用 GROUPING(),再组合判断层级。
-
GROUPING(dept) = 1 AND GROUPING(emp) = 0→ 部门小计(该行 dept 为 NULL,emp 有值) -
GROUPING(dept) = 0 AND GROUPING(emp) = 1→ 员工维度不存在小计(ROLLUP 中 emp 在 dept 后,此组合不会出现) -
GROUPING(dept) = 1 AND GROUPING(emp) = 1→ 总计行 -
GROUPING(dept) = 0 AND GROUPING(emp) = 0→ 明细行
示例:
SELECT
CASE
WHEN GROUPING(dept) = 1 THEN '总计'
WHEN GROUPING(emp) = 1 THEN '部门小计:' || dept
ELSE emp
END AS display_name,
SUM(salary) AS total_salary
FROM employees
GROUP BY ROLLUP(dept, emp);
GROUPING() 与 COALESCE/IS NULL 的本质区别
COALESCE(dept, '小计') 或 dept IS NULL 无法区分 NULL 来源——原始数据里 dept 真是 NULL 时,也会被误标为小计。而 GROUPING(dept) 是 SQL 标准定义的元信息函数,只响应汇总逻辑生成的占位 NULL。
性能上无额外开销,它是聚合执行阶段内置计算,不增加扫描或排序成本。但注意:不同数据库对 GROUPING() 的支持程度略有差异——MySQL 8.0+、PostgreSQL 9.5+、SQL Server、Oracle 均支持;SQLite 不支持。
嵌套 ROLLUP 或多维 CUBE 时 GROUPING 位掩码技巧
当 GROUP BY ROLLUP(a,b,c) 产生多级小计,手动写 GROUPING(a)=1 AND GROUPING(b)=1 AND GROUPING(c)=0 易出错。更稳妥的方式是使用位运算(如果数据库支持 GROUPING_ID())或预计算位掩码:
例如 PostgreSQL 支持 GROUPING(a,b,c) 返回整数,其二进制每位对应一列(从左到右),GROUPING(a,b,c) = 3 即 011,表示 a 未汇总(0)、b 和 c 已汇总(1)。但最通用写法仍是逐列判断——兼容性最好,也最直观。
容易忽略的是:ROLLUP 的列序直接影响小计层级。写成 ROLLUP(emp, dept) 就会先按员工小计,再按部门小计,和常见业务直觉相反。顺序错了,GROUPING() 的组合逻辑就得重推。

















