SQL中的GROUP BY子句用于将查询结果按照一个或多个字段进行分组,配合聚合函数可以完成各类数据统计需求。当单一字段分组无法满足统计维度要求时,就需要使用多列分组来实现更细粒度的数据聚合。

SQL多列分组的基本语法
多列分组的语法和单列分组类似,只需要在GROUP BY关键字后依次列出需要分组的字段即可,多个字段之间用英文逗号分隔。基本语法格式如下:
-- 多列分组基本语法 SELECT 分组字段1, 分组字段2, 聚合函数(统计字段) FROM 表名 WHERE 过滤条件 GROUP BY 分组字段1, 分组字段2 HAVING 分组后过滤条件 ORDER BY 排序字段;
这里需要注意,SELECT后面出现的非聚合字段,必须全部出现在GROUP BY的分组字段列表中,否则查询会报错。分组时数据库会先按照第一个字段进行分组,在第一个字段相同的分组内,再按照第二个字段进行二次分组,以此类推完成多列分组逻辑。
多列分组配合聚合函数的使用案例
假设我们有一张销售记录表sales_record,表结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | int | 记录ID |
| region | varchar | 销售区域 |
| product_type | varchar | 产品类型 |
| sale_amount | decimal | 销售金额 |
| sale_date | date | 销售日期 |
现在需要统计每个区域下每个产品类型的总销售金额,就可以使用多列分组实现:
-- 统计每个区域每个产品类型的总销售额 SELECT region, product_type, SUM(sale_amount) AS total_sales FROM sales_record GROUP BY region, product_type ORDER BY region, total_sales DESC;
上述查询会先按照region字段分组,再在每个区域分组内按照product_type分组,最后对每个最小分组内的sale_amount求和,得到每个区域每个产品类型的销售总额。
多列分组的常见注意事项
分组字段的顺序影响结果吗
分组字段的顺序不会影响最终的聚合结果,只会影响默认排序的逻辑。比如GROUP BY region, product_type和GROUP BY product_type, region得到的分组聚合数值是完全一致的,只是如果不指定ORDER BY的话,默认展示顺序会有区别。
多列分组后如何过滤结果
多列分组后如果需要过滤聚合结果,要使用HAVING子句,而不是WHERE子句。WHERE子句是在分组前对原始数据进行过滤,HAVING是在分组后对聚合结果进行过滤。比如要筛选出总销售额大于10000的区域产品组合:
-- 筛选总销售额大于10000的分组 SELECT region, product_type, SUM(sale_amount) AS total_sales FROM sales_record GROUP BY region, product_type HAVING total_sales > 10000 ORDER BY total_sales DESC;
多列分组可以和单字段分组混合使用吗
不可以,GROUP BY后面的所有字段共同构成一个分组维度,不能部分字段生效部分不生效。如果既需要单字段分组统计又需要多字段分组统计,需要分别写两个查询语句,或者使用UNION ALL合并结果。
特殊场景:包含NULL值的多列分组
如果分组字段中存在NULL值,数据库会把所有NULL值归为同一个分组。比如region字段存在NULL值,那么所有region为NULL的记录会分到同一个组,再和product_type进行二次分组。如果不需要统计NULL值相关的分组,可以在WHERE子句中提前过滤:
-- 过滤掉region为NULL的记录后再分组 SELECT region, product_type, SUM(sale_amount) AS total_sales FROM sales_record WHERE region IS NOT NULL GROUP BY region, product_type;