🔗 MySQL UNION 操作符

联合查询和结果合并的完整指南

UNION 操作符简介

MySQL UNION 操作符用于合并两个或多个 SELECT 语句的结果集。UNION 操作符会自动去除重复的行,而 UNION ALL 则保留所有行包括重复的。

UNION 的特点:
  • 合并多个查询结果
  • 自动去除重复行
  • 要求列数和数据类型匹配
  • 按第一个查询的列名返回结果

基本语法

UNION 语法

SELECT column1, column2, ... FROM table1 UNION SELECT column1, column2, ... FROM table2;

UNION ALL 语法

SELECT column1, column2, ... FROM table1 UNION ALL SELECT column1, column2, ... FROM table2;
注意事项:
  • 每个 SELECT 语句必须有相同数量的列
  • 对应列的数据类型必须兼容
  • 列名以第一个 SELECT 语句为准

实际示例

示例数据准备

-- 创建示例表 CREATE TABLE customers ( id INT PRIMARY KEY, name VARCHAR(50), city VARCHAR(50) ); CREATE TABLE suppliers ( id INT PRIMARY KEY, name VARCHAR(50), city VARCHAR(50) ); -- 插入测试数据 INSERT INTO customers VALUES (1, '张三', '北京'), (2, '李四', '上海'), (3, '王五', '广州'); INSERT INTO suppliers VALUES (1, '供应商A', '北京'), (2, '供应商B', '深圳'), (3, '张三', '北京');

基本 UNION 查询

-- 合并客户和供应商的城市列表(去重) SELECT city FROM customers UNION SELECT city FROM suppliers;
city
北京
上海
广州
深圳

UNION ALL 查询

-- 合并客户和供应商的城市列表(保留重复) SELECT city FROM customers UNION ALL SELECT city FROM suppliers;
city
北京
上海
广州
北京
深圳
北京

高级用法

带条件的 UNION

-- 合并特定条件的结果 SELECT name, city, 'Customer' as type FROM customers WHERE city = '北京' UNION SELECT name, city, 'Supplier' as type FROM suppliers WHERE city = '北京';

UNION 与 ORDER BY

-- 对合并结果排序 (SELECT name, city FROM customers) UNION (SELECT name, city FROM suppliers) ORDER BY city, name;

UNION 与 LIMIT

-- 限制合并结果数量 (SELECT name, city FROM customers LIMIT 2) UNION (SELECT name, city FROM suppliers LIMIT 2) LIMIT 3;

多个表的 UNION

-- 合并三个或更多查询结果 SELECT name FROM customers UNION SELECT name FROM suppliers UNION SELECT name FROM employees;

UNION vs UNION ALL

特性 UNION UNION ALL
重复行处理 自动去除重复行 保留所有行
性能 较慢(需要去重) 较快(无需去重)
使用场景 需要唯一结果 需要所有数据

实际应用场景

1. 数据整合

-- 整合不同来源的用户数据 SELECT user_id, username, 'web' as source FROM web_users UNION ALL SELECT user_id, username, 'mobile' as source FROM mobile_users;

2. 报表生成

-- 生成销售汇总报表 SELECT '本月销售' as period, SUM(amount) as total FROM sales WHERE MONTH(sale_date) = MONTH(NOW()) UNION ALL SELECT '上月销售' as period, SUM(amount) as total FROM sales WHERE MONTH(sale_date) = MONTH(NOW()) - 1 UNION ALL SELECT '本年销售' as period, SUM(amount) as total FROM sales WHERE YEAR(sale_date) = YEAR(NOW());

3. 数据迁移

-- 合并历史数据和当前数据 SELECT order_id, customer_id, order_date FROM current_orders UNION ALL SELECT order_id, customer_id, order_date FROM archived_orders;

性能优化建议

优化技巧:
  • 优先使用 UNION ALL(如果不需要去重)
  • 在子查询中使用适当的索引
  • 避免在大表上进行复杂的 UNION 操作
  • 考虑使用临时表存储中间结果
  • 合理使用 LIMIT 限制结果集大小
注意事项:
  • UNION 操作可能消耗大量内存
  • 过多的 UNION 会影响查询性能
  • 确保数据类型兼容性
  • 注意 NULL 值的处理

常见错误和解决方案

1. 列数不匹配

-- 错误示例 SELECT name, city FROM customers UNION SELECT name FROM suppliers; -- 错误:列数不匹配 -- 正确示例 SELECT name, city FROM customers UNION SELECT name, city FROM suppliers;

2. 数据类型不兼容

-- 错误示例 SELECT id, name FROM customers UNION SELECT name, id FROM suppliers; -- 错误:数据类型不匹配 -- 正确示例 SELECT id, name FROM customers UNION SELECT id, name FROM suppliers;

3. ORDER BY 使用错误

-- 错误示例 SELECT name FROM customers ORDER BY name UNION SELECT name FROM suppliers; -- 错误:ORDER BY 位置错误 -- 正确示例 (SELECT name FROM customers) UNION (SELECT name FROM suppliers) ORDER BY name;