GROUPING SETS 是 PostgreSQL 15 中 GROUP BY 的语法扩展,非函数;必须写为 GROUP BY GROUPING SETS ((a), (a,b), ()),配合 GROUPING() 区分占位 NULL 与真实 NULL,MySQL 8.4 仍不支持。

PostgreSQL 15 完全支持 GROUPING SETS,它不是函数,而是 GROUP BY 子句的语法扩展;用错位置或当成函数调用(比如写成 GROUPING_SETS())会直接报 ERROR: syntax error at or near "GROUPING"。
GROUPING SETS 的括号嵌套和空集写法
每个分组集必须用独立括号包裹,不能省略、不能多层嵌套,也不能混用表达式——例如 (dept, UPPER(region)) 在多数 PostgreSQL 版本中不被允许(需先在 SELECT 或子查询中计算)。
-
()表示“零维度分组”,即全表聚合行,必须显式写出,不能用GROUP BY ()替代整个GROUPING SETS块 - 多个分组集之间用逗号分隔,末尾不能加逗号(否则 PostgreSQL 报
ERROR: syntax error at or near ")") - 字段顺序不影响聚合逻辑,但会影响
GROUPING()返回值的位序(尤其配合GROUPING_ID()时)
必须用 GROUPING() 区分 NULL 是占位还是真实数据
PostgreSQL 不会自动标记哪一行是“部门小计”、哪一行是“原始 dept 为 NULL 的记录”。只靠 dept IS NULL 判断必然出错。
-
GROUPING(dept)返回0表示该行按dept分了组,返回1表示dept是占位NULL - 组合判断推荐用
CASE+GROUPING(),例如:CASE WHEN GROUPING(dept)=1 AND GROUPING(region)=0 THEN 'region_only' END - 如果用了
COALESCE(dept, '[Unknown]')展示,不能用这个结果列参与GROUPING()判断——函数参数必须是原始列名
子查询预处理时要清除原始 NULL
当需要先做维度归并(如把多个产品类型映射为大类)、时间截断(DATE_TRUNC('month', order_time))再走 GROUPING SETS,必须在子查询里处理掉原始 NULL,否则外层 GROUPING() 会失效。
- 错误写法:
SELECT product_type, ... FROM (SELECT CASE WHEN category IN ('A','B') THEN 'Group1' END AS product_type FROM sales) t GROUP BY GROUPING SETS ((product_type))—— 若原始category不匹配任何分支,product_type就是NULL,GROUPING(product_type)仍返回0,无法识别这是“未参与分组” - 正确写法:子查询中强制补缺,如
CASE WHEN category IN ('A','B') THEN 'Group1' ELSE '[Other]' END AS product_type - 性能提示:PostgreSQL 12+ 支持
MATERIALIZEDCTE,对重子查询建议显式声明,避免多次执行
ROLLUP 和 CUBE 是语法糖,不是替代方案
ROLLUP(a,b) 等价于 GROUPING SETS ((a,b), (a), ()),但它不包含 (b);CUBE(a,b) 等价于 GROUPING SETS ((a,b), (a), (b), ())。想精确控制哪些组合出现,必须用 GROUPING SETS。
- 误用
ROLLUP(country, region, city)想获得“仅 region 汇总”?不行——它只出(country,region,city)、(country,region)、(country)、()四种,没有纯region行 -
CUBE在高基数字段上极易爆炸,例如CUBE(user_id, product_id)在百万级表上可能生成亿级分组行,PostgreSQL 会 OOM 或超时 - MySQL 用户注意:截至 2026 年 10 月,MySQL 8.4 仍不支持
GROUPING SETS,强行使用报ERROR 1064,别抄 PostgreSQL 写法
最容易被忽略的是:所有参与 GROUPING SETS 的列,都必须出现在 SELECT 列表中(或作为 GROUPING() 参数),否则 PostgreSQL 报 ERROR: column "xxx" must appear in the GROUP BY clause or be used in an aggregate function;这个限制比普通 GROUP BY 更严格。

















