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 的核心规则是:

  1. 列数必须相同:两个 SELECT 语句的列数必须一致。
  2. 数据类型需兼容:对应列的数据类型需匹配或可隐式转换。例如,INTEGERBIGINT 可以合并,但 VARCHARDATE 则会引发错误。

比喻
将两个书架上的书籍合并到一个新书架时,必须确保每本书都有相同的分类(列数)和格式(数据类型),否则无法整齐排列。


1.3 列名继承规则

合并后的结果集会继承 第一个 SELECT 语句的列名。例如:

SELECT id AS "User ID", name FROM users  
UNION  
SELECT user_id, username FROM customers;  

最终结果的列名会是 "User ID"name,而非第二个查询的 user_idusername


二、UNION 与 UNION ALL 的区别

2.1 核心差异:是否去重

  • UNION:自动去重,效率较低(需额外计算重复行)。
  • UNION ALL:直接合并所有行,保留重复数据,速度更快。

案例对比
假设有两个表 orders_2023orders_2024,均包含 order_idamount 列。若某订单在两年中被重复记录:

-- 使用 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(线下订单)。需生成一份包含所有订单的汇总报告,要求:

  1. 显示订单 ID、金额、销售渠道(线上或线下)。
  2. 去除重复的订单记录。

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_idamountchannel
1001200Online
1002150Offline
1003300Online

关键点

  • 通过 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;  
    
  • 分页需结合 LIMITOFFSET,但需确保排序已明确。

五、高级技巧:与子查询、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_employeescontractors 表中。

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 结果示例

departmenttotal_employees
Sales15
IT10

关键点

  • 使用 UNION ALL 保留所有记录,再通过 GROUP BY 统计总数。
  • 子查询确保数据合并后的完整性。

结论

PostgreSQL UNION 操作符 是数据整合的高效工具,尤其适用于跨表查询、去重合并及多源数据汇总。通过掌握其语法规则、性能差异(UNION vs UNION ALL)及高级技巧,开发者可以更灵活地应对复杂的数据需求。

无论是简化查询逻辑,还是优化数据处理流程,UNION 都能在保持代码简洁性的同时,提升开发效率。建议读者通过实际项目练习,逐步深入理解其应用场景与优化策略。

最新发布