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;