乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 数据库基础与安装

    • MySQL 简介
    • MySQL 5.6 到 5.7 到 8.0 关键差异速查
    • 安装 MySQL 5.7
    • 连接与断开服务器
    • 创建数据库
    • 创建数据表
    • 数据库与数据表
    • 加载数据
    • 获取数据库信息
    • 批处理模式
    • SHOW 语句汇总
    • FLUSH 与 RESET 语句
    • my.cnf 核心参数
    • 字符集与排序规则
  • 第2章 SQL基础查询

    • SELECT
    • WHERE
    • ORDER BY
    • LIMIT
    • COUNT
    • 聚合函数
    • 比较运算符
    • 逻辑运算符
    • 算术运算符
    • 模式匹配
    • NULL 值处理
    • UPDATE
    • DELETE
    • REPLACE
    • SELECT INTO
  • 第3章 数据类型与运算符

    • 数值类型
    • 字符串类型
    • 日期时间类型
    • BIT 类型
    • ENUM 类型
    • SET 类型
    • JSON 类型
    • 类型转换
  • 第4章 函数与表达式

    • 字符串函数
    • 数值函数
    • 日期函数
    • 全文检索函数
  • 第5章 高级查询与子查询

    • JOIN
    • 子查询
    • UNION
    • GROUP BY
    • HAVING
    • DISTINCT
  • 第6章 表与索引

    • 数据定义语言
    • 修改表结构
    • 视图
    • 修改视图与检查选项
    • 外键
    • 索引
    • 唯一索引
    • 复合索引
    • 存储引擎对比
    • 分区表
    • 第一范式与第二范式
    • 第三范式与 BC 范式
    • 反范式设计
  • 第7章 存储过程与函数

    • 存储过程
    • 存储函数
    • 变量
    • 流程控制
    • 游标
    • 预处理语句
  • 第8章 事务与锁

    • 事务
    • 事务隔离级别
    • 锁机制
    • MVCC
    • 死锁专题分析
    • LOCK TABLES
    • XA 事务
  • 第9章 用户管理与安全

    • 用户管理
    • 权限管理
    • 角色
    • SQL 注入防范
  • 第10章 性能优化入门

    • 执行计划
    • 索引优化
    • 查询优化
    • 查询优化器提示
    • 慢查询日志
    • InnoDB 深入机制
    • InnoDB 专项优化
    • Performance Schema
    • sys Schema
  • 第11章 复制与高可用

    • 主从复制原理
    • 半同步复制配置
    • binlog 开启与 point-in-time 恢复
    • mysqldump 全库备份
    • mysqldump 单表与条件备份
    • mysqldump 恢复与导入
    • xtrabackup 全量热备
    • xtrabackup 准备与恢复
    • xtrabackup 增量与流式备份
  • 第12章 触发器与事件

    • 触发器
    • 事件调度器
  • 参考

    • MySQL 5.7 专业术语大全
    • MySQL 5.7 关键字与保留字大全

UNION

导学

有时你需要把两个结构相同但来源不同的查询结果合并在一起展示。UNION 就是做这个的——它像胶水一样把多个 SELECT 的结果纵向拼接。

定义

UNION:用于合并两个或多个 SELECT 语句的结果集。被合并的查询必须拥有相同数量的列,且对应列的数据类型兼容。

核心语法

SELECT 列1, 列2 FROM 表A
UNION [ALL]
SELECT 列1, 列2 FROM 表B
[ORDER BY 列1];
  • UNION:合并后去重,性能开销较大
  • UNION ALL:合并后不去重,性能更好

完整示例准备:建表与数据

CREATE TABLE employees (
    emp_id INT PRIMARY KEY AUTO_INCREMENT,
    emp_name VARCHAR(20),
    dept VARCHAR(20),
    score DECIMAL(5,2)
);

INSERT INTO employees (emp_name, dept, score) VALUES
('大翔', '技术部', 100),
('白歌', '技术部', NULL);

完整示例一:UNION ALL 合并不同条件的结果

当前数据状态

employees 表:

emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

执行 UNION ALL

SELECT emp_name, score, '有分数' AS 类别 FROM employees WHERE score IS NOT NULL
UNION ALL
SELECT emp_name, score, '无分数' AS 类别 FROM employees WHERE score IS NULL;

操作后的结果

emp_namescore类别
大翔100.00有分数
白歌NULL无分数

结果解读

  • UNION ALL 直接将两个 SELECT 的结果纵向拼接
  • 共 1 + 1 = 2 行,保留所有行
  • 使用常量列 '有分数' 和 '无分数' 标识数据来源

完整示例二:UNION 与 UNION ALL 的区别对比

当前数据状态

基于上面的 employees 表。

执行 UNION(去重)

SELECT emp_name, dept FROM employees
UNION
SELECT emp_name, dept FROM employees;

操作后的结果

emp_namedept
大翔技术部
白歌技术部

执行 UNION ALL(不去重)

SELECT emp_name, dept FROM employees
UNION ALL
SELECT emp_name, dept FROM employees;

操作后的结果

emp_namedept
大翔技术部
白歌技术部
大翔技术部
白歌技术部

结果解读对比

特性UNIONUNION ALL
结果行数2 行(去重后)4 行(保留重复)
性能需要创建临时表并去重,性能开销大直接追加结果,性能更好
适用场景需要确保结果唯一时确定无重复或允许重复时
  • UNION 需要去重,MySQL 会创建临时表并做唯一性检查
  • 如果业务上确定没有重复(或允许重复),务必使用 UNION ALL

完整示例三:UNION 后的排序

当前数据状态

基于上面的 employees 表。

执行 UNION ALL 并排序

SELECT emp_name, score, '正式员工' AS 类型 FROM employees WHERE score >= 90
UNION ALL
SELECT emp_name, score, '待考核' AS 类型 FROM employees WHERE score IS NULL
ORDER BY score DESC;

操作后的结果

emp_namescore类型
大翔100.00正式员工
白歌NULL待考核

结果解读

  • ORDER BY 必须放在最后,对整个合并后的结果集排序
  • 不能对每个 SELECT 单独加 ORDER BY(除非用括号 + LIMIT,不推荐)
  • 先按 score 降序排列,NULL 排在最后

完整示例四:列数不同导致的错误

当前数据状态

基于上面的 employees 表。

错误写法演示

-- 错误:列数不匹配
SELECT emp_name FROM employees
UNION
SELECT emp_name, dept FROM employees;

报错信息

ERROR 1222 (21000): The used SELECT statements have a different number of columns

正确写法

-- 正确:列数必须相同
SELECT emp_name, dept FROM employees
UNION
SELECT emp_name, dept FROM employees;

结果解读

  • 被合并的查询必须拥有相同数量的列
  • 对应列的数据类型必须兼容
  • 结果列名取第一个 SELECT 的列名(或别名)

完整示例五:列类型不兼容的对比

当前数据状态

基于上面的 employees 表。

类型兼容的写法

SELECT emp_id, emp_name FROM employees
UNION ALL
SELECT emp_id, emp_name FROM employees;

操作后的结果

emp_idemp_name
1大翔
2白歌
1大翔
2白歌

结果解读

  • emp_id 和 emp_name 在两个查询中类型一致,可以正常合并
  • 如果类型不兼容(如一个 INT 一个 VARCHAR),MySQL 会尝试隐式类型转换,可能产生警告或错误

完整示例六:UNION 与 ORDER BY 和 LIMIT 的配合

当前数据状态

基于上面的 employees 表。

执行查询

SELECT emp_name, score, '高分' AS 类别 FROM employees WHERE score >= 90
UNION ALL
SELECT emp_name, score, '其他' AS 类别 FROM employees WHERE score IS NULL
ORDER BY score DESC
LIMIT 2;

操作后的结果

emp_namescore类别
大翔100.00高分
白歌NULL其他

结果解读

  • ORDER BY 放在最后,对合并后的整个结果集排序
  • LIMIT 限制最终返回的行数
  • 取所有记录中按 score 排序的前 2 条

完整示例七:UNION 与 JOIN 的区别对比

当前数据状态

基于上面的 employees 表。

UNION 纵向合并

SELECT emp_name, score FROM employees WHERE score >= 90
UNION ALL
SELECT emp_name, score FROM employees WHERE score IS NULL;

结果:2 行,每行有 emp_name 和 score 两列。

JOIN 横向拼接

SELECT a.emp_name, a.score AS score_a, b.score AS score_b
FROM employees a
LEFT JOIN employees b ON a.emp_id = b.emp_id AND b.score IS NOT NULL;

操作后的结果

emp_namescore_ascore_b
大翔100.00100.00
白歌NULLNULL

结果解读对比

特性UNIONJOIN
方向纵向合并(增加行)横向拼接(增加列)
列数要求两个查询列数必须相同不要求列数相同
连接条件不需要连接条件需要 ON 条件
适用场景合并同类数据关联不同表的数据

常见误区

误区正解
UNION 和 UNION ALL 一样UNION 去重慢,UNION ALL 不去重快。确定无重复时用 ALL。
每个 SELECT 都可以加 ORDER BY只有最后一个 SELECT 后面可以加 ORDER BY,对整个结果集生效。
列名不一致没关系列数必须相同,类型必须兼容。结果列名取第一个 SELECT 的列名。

面试考点

Q:UNION 和 JOIN 的区别?

UNION 是纵向合并(增加行),要求列数相同;JOIN 是横向拼接(增加列),要求有连接条件。

Q:为什么 UNION ALL 比 UNION 快?

UNION 需要创建临时表并对合并结果去重(类似 DISTINCT),涉及哈希或排序操作;UNION ALL 直接追加结果,无需去重。

Q:UNION 结果集的列名由谁决定?

由第一个 SELECT 语句的列名(或别名)决定。

小结

  • UNION 纵向合并多个 SELECT 的结果
  • UNION ALL 不去重,性能优于 UNION
  • 被合并的查询必须列数相同、类型兼容
  • 只有最后一个 SELECT 后面可以加全局 ORDER BY

下一章引子:合并了结果集,接下来学习如何对数据进行分组汇总——GROUP BY。

上一页
子查询
下一页
GROUP BY