group by 仅分组聚合,不生成报表层级;多层级报表需结合 with rollup 或 grouping sets 补全汇总行,并严格满足非聚合字段全列于 group by 中、用 grouping() 区分占位 null 与真实 null 等硬性条件。

GROUP BY 本身不生成“报表层级”,它只做分组聚合;所谓多层级报表,本质是按字段优先级切分 + 用 WITH ROLLUP / GROUPING SETS 补全汇总行。
GROUP BY field1, field2, field3 怎么写才不出错
直接写 GROUP BY region, city, shop 就行,但必须满足两个硬性条件:
- 所有非聚合字段(即没套
COUNT()、SUM()等的字段)必须完整出现在GROUP BY列表中,漏一个就报错:Expression #2 of SELECT list is not in GROUP BY clause - 字段顺序不影响逻辑结果,但影响输出行的物理排列——比如
GROUP BY city, region和GROUP BY region, city返回的行序不同,若需稳定排序,必须显式加ORDER BY -
NULL默认视为相同值参与分组,无需额外处理;但若想把NULL当作“未知”合并进其他组,得先用CASE WHEN field IS NULL THEN 'N/A' ELSE field END转换
WITH ROLLUP 生成小计和总计的注意事项
GROUP BY region, city, shop WITH ROLLUP 会产出四层结果:(region, city, shop)、(region, city, NULL)、(region, NULL, NULL)、(NULL, NULL, NULL)。关键点在于:
-
NULL行不是数据缺失,而是语法标记,表示“该位置上卷”——(region, NULL, NULL)是某地区的城市小计,不是城市字段为空 - 不能直接在
SELECT里写IFNULL(city, '城市小计'),万一原始数据真有city = '城市小计'就冲突了;正确做法是结合GROUPING(city)判断:CASE WHEN GROUPING(city) = 1 AND GROUPING(region) = 0 THEN '城市小计' ELSE city END -
WITH ROLLUP是 MySQL 特有语法;PostgreSQL 得用GROUPING SETS ((region, city, shop), (region, city), (region), ());SQL Server 两者都支持
为什么 CUBE 或 GROUPING SETS 更适合真正多维报表
当业务要求“同时看城市销量、车型销量、城市+车型组合、以及全局总计”,GROUP BY ... WITH ROLLUP 不够用——它只支持前缀式上卷(如 A→A,B→A,B,C),而 CUBE(a,b) 会产出 ()、(a)、(b)、(a,b) 四种组合,GROUPING SETS 更灵活,可自定义任意组合:
-
GROUPING SETS ((city), (car_model), (city, car_model), ())明确指定四种粒度,不产生冗余分组 -
CUBE是GROUPING SETS的语法糖,CUBE(a,b)≡GROUPING SETS ((a,b), (a), (b), ()),但列数一多(比如 4 列),CUBE会生成 2⁴=16 行,容易爆炸,务必提前过滤或限制维度数 - 所有
NULL占位符都必须用GROUPING()函数识别,否则无法区分真实空值和汇总占位符
权限控制与多层级报表的常见混淆点
很多人以为 GROUP BY region, city WITH ROLLUP 能自动适配“销售员只能看城市、主管能看省份”,这是错的:
- 权限过滤必须在
GROUP BY之前完成,走WHERE region IN (SELECT ...)或数据库原生 RLS(如 PostgreSQL 的CREATE POLICY),否则GROUP BY仍会聚合全量数据 -
WITH ROLLUP生成的(region, NULL)行对所有人可见,它不是权限开关,只是物理汇总标记 - 若要角色驱动的动态层级(如销售员查
GROUP BY city,总监查GROUP BY region),得用不同 SQL,或在应用层根据角色拼接不同GROUP BY子句,而不是依赖同一个查询解释 NULL
真正难的不是语法,而是搞清哪些逻辑该由 SQL 承担(分组、汇总、占位符识别),哪些必须前置过滤(权限)、哪些得靠 BI 工具补全(缺失组合填 0)、哪些需要窗口函数延伸(环比、排名)——混在一起写,迟早出错。











