在实际的数据库查询工作中,我们经常会遇到需要将不同维度、不同筛选条件的分组聚合结果汇总到同一个结果集的情况,比如统计不同部门的销售额,同时还要统计不同地区的销售额,最后把这些数据放在同一个表格里展示。使用UNION ALL可以很好地实现这个需求,它可以将多个独立的查询结果合并起来,并且不会去重,保留所有符合每个查询条件的结果。

UNION ALL的基本使用规则
要使用UNION ALL合并多个分组聚合结果,首先需要满足几个基本条件,否则查询会直接报错:
- 每个独立的查询语句返回的列数必须完全一致,不能有的查询返回2列,有的返回3列
- 对应位置的列的数据类型需要兼容,比如第一个查询的第一列是数值类型,第二个查询的第一列也应该是数值类型或者可以隐式转换为数值类型的类型
- 列的顺序需要一致,通常我们会给每个查询的列设置相同的别名,方便结果集的阅读和理解
结合分组聚合的使用示例
假设我们有一张order_info表,存储了订单的相关信息,表结构如下:
| 列名 | 类型 | 说明 |
|---|---|---|
| order_id | int | 订单ID |
| department | varchar | 所属部门 |
| region | varchar | 所属地区 |
| amount | decimal | 订单金额 |
| create_time | datetime | 订单创建时间 |
现在我们需要同时统计每个部门的订单总金额,以及每个地区的订单总金额,两个结果合并到同一个结果集里,就可以使用以下SQL语句:
-- 统计每个部门的订单总金额
SELECT
'department' AS stat_type,
department AS stat_dimension,
SUM(amount) AS total_amount
FROM order_info
GROUP BY department
UNION ALL
-- 统计每个地区的订单总金额
SELECT
'region' AS stat_type,
region AS stat_dimension,
SUM(amount) AS total_amount
FROM order_info
GROUP BY region;
上面的查询中,第一个查询按部门分组聚合,第二个查询按地区分组聚合,两个查询都返回了3列,列名和顺序完全一致,通过UNION ALL合并后,就会得到包含所有部门统计和所有地区统计的结果集,其中stat_type列可以用来区分当前行是部门统计还是地区统计。
UNION ALL和UNION的区别
很多开发者会混淆UNION和UNION ALL的用法,两者的核心差异在于是否去重:
- UNION:合并多个查询结果后,会对最终的结果集进行去重操作,重复的行只保留一条,这个去重过程需要额外的排序和比较开销,性能相对更低
- UNION ALL:直接合并多个查询结果,不会做任何去重处理,只要符合每个查询条件的结果都会保留,性能更高,适合明确知道结果不会有重复,或者需要保留重复结果的场景
如果上面的示例中使用UNION而不是UNION ALL,当两个分组聚合的结果出现完全相同的stat_type、stat_dimension、total_amount时,重复的行会被删除,可能导致统计结果不符合预期。
注意事项
在使用UNION ALL合并分组聚合结果时,还有几个细节需要注意:
- 如果需要对合并后的整个结果集进行排序,ORDER BY子句只能放在最后一个查询的后面,不能在每个独立的查询中都加ORDER BY,除非每个独立查询用括号包裹并且配合LIMIT使用
- 每个独立查询的聚合函数可以根据需求不同,比如第一个查询用SUM,第二个查询用COUNT,只要返回列的类型兼容即可
- 如果分组聚合的查询中包含WHERE筛选条件,每个查询可以设置自己独立的筛选逻辑,互不影响
比如我们需要统计2024年每个部门的订单总金额,以及所有时间的每个地区的订单总金额,就可以写成下面的形式:
-- 统计2024年每个部门的订单总金额
SELECT
'department' AS stat_type,
department AS stat_dimension,
SUM(amount) AS total_amount
FROM order_info
WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01'
GROUP BY department
UNION ALL
-- 统计所有时间每个地区的订单总金额
SELECT
'region' AS stat_type,
region AS stat_dimension,
SUM(amount) AS total_amount
FROM order_info
GROUP BY region
-- 对合并后的结果按总金额降序排序
ORDER BY total_amount DESC;
通过这种方式,我们可以灵活地将不同条件、不同分组维度的聚合结果合并起来,满足复杂的数据统计需求。