PostgreSQL UNION 操作符(建议收藏)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言
在数据库查询的世界中,如何将多个查询结果合并为一个统一的数据集,是开发者常遇到的挑战。PostgreSQL UNION 操作符正是为解决这一问题而生。它允许开发者将两个或多个 SELECT
语句的结果合并,并自动去除重复的行。无论是数据整合、报告生成,还是复杂查询的中间步骤,UNION 都是数据库工程师的得力工具。
本文将从基础语法到实际案例,逐步解析 PostgreSQL UNION 操作符 的使用场景、核心规则及进阶技巧。通过对比、比喻和代码示例,帮助读者快速掌握这一操作符的精髓。
一、PostgreSQL UNION 操作符的基础语法
1.1 语法结构
UNION 的基本语法如下:
SELECT column1, column2, ... FROM table1
UNION
SELECT column1, column2, ... FROM table2;
- UNION 默认会去除两个查询结果中的重复行。
- 若需保留重复行,可使用 UNION ALL(后续章节会详细对比两者的区别)。
1.2 数据类型与列数匹配规则
UNION 的核心规则是:
- 列数必须相同:两个
SELECT
语句的列数必须一致。 - 数据类型需兼容:对应列的数据类型需匹配或可隐式转换。例如,
INTEGER
和BIGINT
可以合并,但VARCHAR
和DATE
则会引发错误。
比喻:
将两个书架上的书籍合并到一个新书架时,必须确保每本书都有相同的分类(列数)和格式(数据类型),否则无法整齐排列。
1.3 列名继承规则
合并后的结果集会继承 第一个 SELECT 语句的列名。例如:
SELECT id AS "User ID", name FROM users
UNION
SELECT user_id, username FROM customers;
最终结果的列名会是 "User ID"
和 name
,而非第二个查询的 user_id
和 username
。
二、UNION 与 UNION ALL 的区别
2.1 核心差异:是否去重
- UNION:自动去重,效率较低(需额外计算重复行)。
- UNION ALL:直接合并所有行,保留重复数据,速度更快。
案例对比:
假设有两个表 orders_2023
和 orders_2024
,均包含 order_id
和 amount
列。若某订单在两年中被重复记录:
-- 使用 UNION 会过滤重复订单
SELECT order_id, amount FROM orders_2023
UNION
SELECT order_id, amount FROM orders_2024;
-- 使用 UNION ALL 保留所有记录(包括重复)
SELECT order_id, amount FROM orders_2023
UNION ALL
SELECT order_id, amount FROM orders_2024;
2.2 性能考量
- 当数据量较大且重复率低时,优先使用 UNION ALL,再通过其他方式处理重复。
- 若必须去重,则 UNION 是更简洁的选择。
三、实际案例:合并销售数据
3.1 案例背景
某电商平台有两个销售表:online_sales
(线上订单)和 offline_sales
(线下订单)。需生成一份包含所有订单的汇总报告,要求:
- 显示订单 ID、金额、销售渠道(线上或线下)。
- 去除重复的订单记录。
3.2 SQL 实现
SELECT
order_id,
amount,
'Online' AS channel
FROM online_sales
UNION
SELECT
order_id,
amount,
'Offline' AS channel
FROM offline_sales;
3.3 结果展示
order_id | amount | channel |
---|---|---|
1001 | 200 | Online |
1002 | 150 | Offline |
1003 | 300 | Online |
关键点:
- 通过
AS channel
明确销售渠道,提升可读性。 - UNION 自动过滤
order_id
相同的重复订单(如线上和线下出现相同订单 ID 时)。
四、注意事项与常见问题
4.1 数据类型不匹配
若两列的数据类型不兼容,PostgreSQL 会报错。例如:
SELECT '2023-01-01'::DATE AS date_col
UNION
SELECT 2023 AS number_col;
错误提示:cannot mix SELECT expressions with types date and integer in UNION
.
解决方案:
- 显式转换数据类型:
SELECT '2023-01-01'::DATE UNION SELECT 2023::DATE; -- 将整数转换为 DATE 类型
4.2 空值(NULL)的处理
UNION 会将 NULL
视为相同值。例如:
SELECT NULL AS col1, 1 AS col2
UNION
SELECT NULL, 1;
结果只会返回一行,因为两行完全相同。
4.3 排序与分页
- UNION 结果默认无序,若需排序,需在最后添加
ORDER BY
:( SELECT * FROM table1 UNION SELECT * FROM table2 ) ORDER BY amount DESC;
- 分页需结合
LIMIT
和OFFSET
,但需确保排序已明确。
五、高级技巧:与子查询、DISTINCT 结合
5.1 结合子查询
UNION 可嵌套在子查询中,实现多级合并。例如:
SELECT * FROM (
SELECT 'A' AS category, 'Product1' AS name
UNION
SELECT 'B', 'Product2'
) AS combined
WHERE category = 'A';
5.2 替代 DISTINCT 的场景
当需要去重但数据分散在多个表时,UNION 可简化查询:
-- 直接合并并去重
SELECT id FROM table1
UNION
SELECT id FROM table2;
-- 等效于(但更繁琐)
SELECT DISTINCT id FROM (
SELECT id FROM table1
UNION ALL
SELECT id FROM table2
) AS temp;
六、进阶案例:动态数据合并
6.1 场景描述
某公司需要统计不同部门的员工总数,但员工信息分散在 hr_employees
和 contractors
表中。
6.2 SQL 实现
SELECT
department,
COUNT(*) AS total_employees
FROM (
SELECT department FROM hr_employees
UNION ALL
SELECT department FROM contractors
) AS all_employees
GROUP BY department;
6.3 结果示例
department | total_employees |
---|---|
Sales | 15 |
IT | 10 |
关键点:
- 使用
UNION ALL
保留所有记录,再通过GROUP BY
统计总数。 - 子查询确保数据合并后的完整性。
结论
PostgreSQL UNION 操作符 是数据整合的高效工具,尤其适用于跨表查询、去重合并及多源数据汇总。通过掌握其语法规则、性能差异(UNION vs UNION ALL)及高级技巧,开发者可以更灵活地应对复杂的数据需求。
无论是简化查询逻辑,还是优化数据处理流程,UNION 都能在保持代码简洁性的同时,提升开发效率。建议读者通过实际项目练习,逐步深入理解其应用场景与优化策略。