MySQL 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+ 小伙伴加入学习 ,欢迎点击围观
在数据库操作中,经常需要将两个或多个查询结果合并为一个统一的数据集。此时,MySQL UNION 操作符
就像一把灵活的瑞士军刀,能够帮助开发者高效整合数据。无论是报表生成、多表聚合还是复杂查询场景,UNION
都是提升开发效率的核心工具之一。对于编程初学者,理解其基础语法和逻辑是关键;而对中级开发者,掌握其性能优化和进阶用法则能进一步提升技术深度。
一、基础语法与核心逻辑
1.1 基本语法结构
UNION
操作符用于合并两个或多个 SELECT
语句的结果集。其核心语法如下:
SELECT column1, column2, ...
FROM table1
UNION
SELECT column1, column2, ...
FROM table2;
关键规则:
- 所有
SELECT
语句的列数必须一致。 - 对应列的 数据类型 必须兼容(如整数与浮点数可合并,但字符串与数值类型不可合并)。
- 列名以第一个
SELECT
的列名为准。
形象比喻:可以将 UNION
视为“合并两个文件夹”的操作。假设两个文件夹分别存放了不同部门的员工信息,UNION
可以将它们合并为一个总文件夹,但会自动删除重复的文件(即去重)。
1.2 UNION 与 UNION ALL 的区别
UNION
默认会 自动去重,而 UNION ALL
则保留所有结果,包括重复行。
示例对比
假设表 employees
和 contractors
各有以下数据:
| employees | contractors |
|------------------|--------------------|
| Alice (ID: 1) | Bob (ID: 2) |
| Bob (ID: 2) | Charlie (ID: 3) |
执行以下查询:
SELECT name FROM employees
UNION
SELECT name FROM contractors;
结果会是:
| name |
|--------|
| Alice |
| Bob |
| Charlie|
而使用 UNION ALL
:
SELECT name FROM employees
UNION ALL
SELECT name FROM contractors;
结果会包含重复的 Bob
:
| name |
|--------|
| Alice |
| Bob |
| Charlie|
| Bob |
性能提示:如果明确知道数据无重复或无需去重,建议使用 UNION ALL
,因为去重操作会消耗额外的计算资源。
二、使用场景与实际案例
2.1 合并不同表的同类数据
场景:公司有两个部门表,需要统计所有员工的姓名和邮箱。
表结构:
department_a
包含name
和email
列。department_b
包含full_name
(即姓名)和contact_email
(即邮箱)列。
解决方案:
SELECT name, email
FROM department_a
UNION
SELECT full_name, contact_email
FROM department_b;
注意:虽然列名不同,但只要数据类型一致,UNION
仍可合并。结果列名以第一个 SELECT
的列名为准(即 name
和 email
)。
2.2 生成动态筛选条件的聚合结果
场景:需要根据用户输入动态拼接查询条件,例如从不同表中筛选出特定地区的用户和商家。
表结构:
users
表有id
,name
,location
列。merchants
表有id
,business_name
,region
列。
查询示例:
SELECT name AS entity_name, location AS area
FROM users
WHERE location = 'Shanghai'
UNION
SELECT business_name AS entity_name, region AS area
FROM merchants
WHERE region = 'Shanghai';
结果将合并两类实体的上海地区信息,便于统一展示。
2.3 处理跨数据库或跨环境的查询
在某些架构中,数据可能分散在不同数据库或实例中。UNION
可以通过跨连接查询合并结果,例如:
SELECT * FROM database1.table1
UNION
SELECT * FROM database2.table2;
但需确保两表结构完全一致。
三、进阶用法与注意事项
3.1 列数与类型的严格匹配
若 SELECT
语句的列数或类型不一致,MySQL 会报错。例如:
SELECT id, name FROM employees -- 两列
UNION
SELECT department FROM departments; -- 一列
此查询会因列数不匹配而失败。
3.2 排序与分页的正确位置
ORDER BY
和 LIMIT
必须 仅出现在最后一个 SELECT
语句之后,否则会因语法错误而失败。例如:
SELECT name FROM employees
UNION
SELECT name FROM contractors
ORDER BY name ASC -- 正确位置
LIMIT 10;
如果将 ORDER BY
放在第一个 SELECT
后面,则会报错。
3.3 性能优化技巧
- 避免不必要的去重:若数据无重复或无需去重,改用
UNION ALL
。 - 索引优化:对参与合并的列(如
name
或id
)建立索引,加速查询。 - 减少列的数量:仅选择必要的列,避免全表扫描。
四、常见问题与解决方案
4.1 问题:合并结果中出现乱序
原因:UNION
默认不保证结果顺序,除非显式使用 ORDER BY
。
解决方案:在最后一个 SELECT
后添加 ORDER BY
子句。
4.2 问题:数据类型不兼容导致错误
示例错误:
ERROR 1292 (22007): Truncated incorrect DOUBLE value: 'Alice'
原因:合并的列中,一个表的列是 VARCHAR
,另一个是 FLOAT
。
解决方案:统一列类型,例如将字符串转换为数值或反之。
五、实战案例:电商订单合并查询
5.1 场景描述
某电商平台有两个订单表:
orders
:普通用户的订单(order_id
,user_id
,amount
)。wholesale_orders
:批发商的订单(order_code
,business_id
,total
)。
需求:统计所有订单的总金额,并按用户/批发商分类。
5.2 解决方案
SELECT
CONCAT('User_', user_id) AS entity_id,
amount AS total_amount
FROM orders
UNION ALL
SELECT
CONCAT('Business_', business_id) AS entity_id,
total AS total_amount
FROM wholesale_orders;
此查询将两类订单合并,通过 CONCAT
统一标识符格式,并保留原始金额字段。
六、总结与扩展
通过本文,我们系统梳理了 MySQL UNION 操作符
的核心语法、使用场景及优化技巧。开发者需注意以下关键点:
- 基础规则:列数、类型匹配,去重逻辑。
- 性能优化:优先使用
UNION ALL
,合理利用索引。 - 复杂场景:通过列别名、函数灵活处理异构数据。
对于进阶学习者,可进一步探索 UNION
与子查询、事务的结合,或结合 CASE
语句实现更复杂的条件合并。实践是掌握该操作符的最佳途径,建议读者通过实际项目或沙箱环境进行验证。
希望本文能成为您数据库技能提升的阶梯,祝您的开发旅程顺利!