GROUPING函数仅在ROLLUP/CUBE分组中有效,返回0(列参与分组)或1(列被虚化为小计/总计占位符),需配合COALESCE或CASE区分真实NULL与系统生成NULL。

GROUPING函数返回值的含义必须结合GROUP BY ROLLUP/CUBE理解
单独用GROUPING()没意义,它只在含ROLLUP或CUBE的分组查询中才有实际作用。它的返回值是0或1:0表示该列参与了当前行的分组依据,1表示该列被“虚化”(即此处是小计/总计行,该列值为NULL但不是原始数据里的NULL)。
常见错误是直接对普通GROUP BY用GROUPING(col),结果全为0——因为没有生成虚化行,自然没有“需要标记的NULL”。
-
GROUPING(dept)为1 → 当前行是跨部门的小计或公司总计,dept列的NULL是系统填充的占位符 -
GROUPING(emp_id)为1 → 说明这行已聚合到比员工更粗的粒度(如部门级),emp_id不参与分组 - 多列时可组合判断:
GROUPING(dept)=1 AND GROUPING(emp_id)=0代表部门小计行(有具体员工?不,此时emp_id也应为NULL;正确逻辑见下一条)
用GROUPING()区分小计、总计与明细行的典型写法
以按部门、员工两级汇总工资为例,需同时识别“员工明细”“部门小计”“公司总计”三类行:
SELECT
CASE
WHEN GROUPING(dept) = 1 AND GROUPING(emp_id) = 1 THEN '公司总计'
WHEN GROUPING(dept) = 0 AND GROUPING(emp_id) = 1 THEN '部门小计'
ELSE '员工明细'
END AS row_type,
COALESCE(dept, 'ALL_DEPTS') AS dept,
COALESCE(emp_id, 'ALL_EMPS') AS emp_id,
SUM(salary) AS total_salary
FROM employees
GROUP BY dept, emp_id WITH ROLLUP;
注意:WITH ROLLUP生成的NULL顺序固定(从右向左虚化),所以GROUPING(emp_id)=1且GROUPING(dept)=0才对应部门小计;反过来GROUPING(dept)=1且GROUPING(emp_id)=0在ROLLUP中不会出现(除非显式GROUP BY emp_id, dept WITH ROLLUP改变顺序)。
- 不要依赖
IS NULL判断小计——原始数据里可能真有NULL部门,会和系统生成的占位NULL混淆 -
GROUPING()是标准SQL函数,但MySQL 5.7+、PostgreSQL 9.5+、SQL Server均支持;SQLite不支持 - Oracle中需用
GROUPING()配合GROUPING SETS,语法略有差异但语义一致
GROUPING_ID()能简化多列组合判断
当分组字段超过2个(比如地区、部门、岗位三级),用嵌套CASE WHEN GROUPING(a)=1 AND GROUPING(b)=0...极易出错。GROUPING_ID()把各列GROUPING()结果拼成二进制再转十进制,直接映射组合状态:
例如GROUP BY region, dept, job WITH ROLLUP,则:
-
GROUPING_ID(region, dept, job) = 0→ 全部非空 → 明细行(region=A, dept=B, job=C) -
GROUPING_ID(region, dept, job) = 1→ 二进制001→job虚化 → 部门小计(region=A, dept=B, job=NULL) -
GROUPING_ID(region, dept, job) = 3→ 二进制011→dept和job虚化 → 地区小计(region=A, dept=NULL, job=NULL) -
GROUPING_ID(region, dept, job) = 7→ 二进制111→ 全虚化 → 总计行
这个数值本身没业务含义,但比写6个AND条件清晰得多。注意参数顺序必须和GROUP BY中完全一致,否则位序错乱。
容易忽略的NULL显示问题与COALESCE陷阱
即使用GROUPING()准确识别了小计行,直接SELECT dept仍会显示NULL,影响报表可读性。常用COALESCE(dept, 'Subtotal'),但这里有个坑:
- 如果原始
dept列允许NULL,COALESCE会把真实NULL和小计占位NULL一并替换,无法区分 - 正确做法是结合
GROUPING()控制显示:CASE WHEN GROUPING(dept)=1 THEN 'Dept Subtotal' ELSE dept END - 某些BI工具(如Tableau)会自动隐藏
GROUPING列,导致后续计算失效——务必在SQL层就完成类型标注,别依赖前端补逻辑
另外,GROUPING()只能用于SELECT和HAVING子句,在WHERE中使用会报错(因为分组前无法确定哪些行会被虚化)。

















