GROUPING()函数仅限ROLLUP/CUBE/GROUPING SETS查询中使用,普通GROUP BY调用会报错;它通过返回0或1标识列是否为聚合生成的占位符NULL,而非原始空值,须配合CASE语句转换标签、参与ORDER BY排序以确保汇总行位置正确。

GROUPING() 函数只能在 ROLLUP/CUBE/GROUPING SETS 查询中用
直接在普通 GROUP BY 里写 GROUPING(col) 会报错:GROUPING() can only be used in a GROUP BY clause with ROLLUP, CUBE or GROUPING SETS。它不是通用判空函数,而是 SQL Server、Oracle、PostgreSQL(>=14)等支持标准 SQL/2003 的数据库为聚合占位符专门设计的元数据读取机制。
常见错误是把它当 IS NULL 替代品——比如在没加 WITH ROLLUP 的查询里硬套,结果连语句都跑不起来。
怎么用 GROUPING() 替换小计行的 NULL 值
关键不是“判断是否为小计”,而是“把小计行的 NULL 显式转成可读标签”,否则报表里全是空值,业务方根本分不清哪是真缺失、哪是汇总占位。
- 对每个参与
ROLLUP的列都要单独处理,例如GROUP BY dept, team WITH ROLLUP,就得同时用GROUPING(dept)和GROUPING(team) - 推荐写法:
CASE WHEN GROUPING(team) = 1 THEN '部门小计' ELSE team END,而不是COALESCE(team, '部门小计')——后者会把原始team IS NULL的记录也标成小计 - 如果多列组合,标签要体现层级,比如
CASE WHEN GROUPING(dept)=1 AND GROUPING(team)=1 THEN '总计' WHEN GROUPING(dept)=0 AND GROUPING(team)=1 THEN dept + '小计' ELSE dept END
ORDER BY 里必须带 GROUPING() 才能保证汇总行位置正确
不控制排序时,ROLLUP 行可能插在明细中间,或者跨分组乱序。比如你想要“部门A所有明细 → 部门A小计 → 部门B所有明细 → 部门B小计 → 全部总计”,就必须让 GROUPING() 参与排序逻辑。
典型写法:ORDER BY dept, GROUPING(team) DESC, team。这里 GROUPING(team) DESC 把 GROUPING(team)=1(小计行)排在同部门明细之后;而 GROUPING(dept) DESC 要放在最前,才能把全表总计压到最后。
漏掉这一步,导出 Excel 后小计行散落各处,核对总数时极易出错——这是上线后最常被反馈的问题。
GROUPING_ID() 是 GROUPING() 的压缩版,但顺序不能错
GROUPING_ID(dept, team) 返回的是二进制位拼接后的十进制数:GROUPING(dept) 是高位,GROUPING(team) 是低位。所以 GROUPING_ID(dept, team) = 1 意味着 GROUPING(dept)=0 且 GROUPING(team)=1(部门小计),而 = 3 表示两者都为 1(总计)。
注意:GROUPING_ID(team, dept) 和 GROUPING_ID(dept, team) 结果不同,参数顺序必须和 GROUP BY 中一致,否则位含义完全错乱。
它适合做 HAVING 过滤或前端分类,比如只取小计行:HAVING GROUPING_ID(dept, team) = 1;但别指望靠它省掉对单列 GROUPING() 的理解——一旦顺序搞反,整个逻辑就崩了。

















