首页/数据/SQL 速查/GROUPING SETS 与 CUBE(PostgreSQL)
聚合与窗口函数54 条

GROUPING SETS 与 CUBE(PostgreSQL)

一条查询同时产出多种分组口径:PostgreSQL 支持 GROUPING SETS 与 CUBE;MySQL 8 只有 ROLLUP。

SQL 速查数据更新于 2026-10-13

GROUPING SETS 与 CUBE 是什么

一条查询同时产出多个分组口径,是报表里的常见诉求:按城市、按状态、以及全表合计一次拿全。PostgreSQL 用 GROUPING SETS 显式列出需要的组合,用 CUBE 生成全部列组合,用 ROLLUP 生成逐级汇总;MySQL 8.0 只支持 ROLLUP,其余口径要靠 UNION ALL 拼装。

基本信息

PostgreSQLGROUPING SETS、CUBE、ROLLUP 三种分组修饰符,且可嵌套书写
MySQL 8.0仅支持 GROUP BY ... WITH ROLLUP,无 GROUPING SETS 与 CUBE
合计行识别用 GROUPING() 函数判断某列在当前行是否参与分组
结果形态单个结果集,各口径的行混在一起,靠标识列与排序区分
成本每个分组组合都要各自扫描与聚合一次

三种口径对照

写法产生的分组组合典型用途
GROUPING SETS ((a), (b), ())只产出显式列出的三个组合口径固定、组合数不多的报表
CUBE (a, b)全组合:(a,b)、(a)、(b)、()两三个维度的任意交叉汇总
ROLLUP (a, b)层级组合:(a,b)、(a)、()省到市、年到月这类上下级汇总
GROUP BY ()只有一个总计组单独取整表合计,等价于不分组

典型使用场景

  • 固定口径报表:按城市、按状态、整表合计三个数字一次查出
  • 交叉分析:两个维度全组合汇总,省掉手写多条语句
  • 层级汇总:省到市、年到月的逐级小计与总计
  • 核对校验:合计行可直接与明细行加总做一致性检查
  • 减少往返:一次查询代替多次分组查询,应用层不再拼接结果
  • 供 BI 落地:单个结果集即可导成一张带口径标识的宽表

PostgreSQL 三种写法

PostgreSQL 三种写法
SELECT city, status, COUNT(*) AS cnt          # 三个口径一次输出
FROM users
GROUP BY GROUPING SETS ((city), (status), ());
SELECT city, status, COUNT(*) AS cnt          # CUBE:两列的全部组合
FROM users
GROUP BY CUBE (city, status)
ORDER BY city NULLS LAST, status NULLS LAST;  # 让合计行排在结果末尾
SELECT city, status, COUNT(*) AS cnt,         # 用 GROUPING 区分合计行
       GROUPING(city) AS g_city, GROUPING(status) AS g_status
FROM users GROUP BY ROLLUP (city, status)
ORDER BY g_city, g_status;                    # 先明细行、再小计、最后总计

结果逐行读法

g_city / g_status含义如何使用
0 / 0两列都参与分组,是最细的明细行正常业务数据行
1 / 0按 status 汇总,city 位显示 NULL该 NULL 是占位符,不是城市为空
0 / 1按 city 汇总,status 位显示 NULL同上,需要按口径过滤
1 / 1总计行,两个维度都不参与分组整表合计,常用于算占比
多口径结果里的 NULL 有两重含义:列本身为空,或者该列在当前口径下不参与分组。两者必须靠 GROUPING() 区分,否则合计行会被下游当成空值行处理,汇总数字会翻倍或串口径。
MySQL 8.0 没有 GROUPING SETS 与 CUBE,常见替代是用 UNION ALL 拼多条分组语句;此时要保证各分支的列数与类型一致,并自行补一个口径标识列,方便下游区分小计与总计。
分组组合越多,扫描与聚合的代价越高:CUBE 的组合数随列数按 2 的幂增长。大表上先想清楚真正需要的口径,能用 GROUPING SETS 枚举就不要用 CUBE 全开。

易错点

  • 把合计行的 NULL 当数据空值:不配合 GROUPING() 判断,下载清洗与关联逻辑会出错
  • CUBE 开的维度太多:组合数按 2 的幂增长,扫描与聚合成本迅速放大
  • 在 MySQL 上找 GROUPING SETS 语法:8.0 不支持,只能靠 UNION ALL 模拟
  • ROLLUP 的列序写反:汇总层级变成另一条链,结果口径与预期完全不符
  • UNION ALL 模拟时各分支列类型不一致:类型推导会把数字变成字符串,聚合口径错乱

数据来源与参考

  • PostgreSQL Documentation · GROUPING SETS
  • MySQL 8.0 Reference Manual · GROUP BY Modifiers
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌