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

    • 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 关键字与保留字大全

ENUM 类型

导学

当你需要存储"有限选项中的一个"时——比如性别、状态、等级——用 VARCHAR 太浪费空间,用 TINYINT 又不够直观。ENUM 类型让你用字符串的形式存储,却只占用 1~2 字节的存储空间,是 MySQL 中非常实用的"字典型"数据类型。

定义

ENUM:枚举类型,用于存储从一个预定义字符串列表中选择的单个值。内部以整数索引存储(1, 2, 3...),对外表现为字符串。

核心语法

CREATE TABLE 表名 (
    列名 ENUM('值1', '值2', '值3', ...) [NOT NULL] [DEFAULT '值1']
);
特性说明
最大成员数65,535 个
存储空间1~2 字节(成员数 ≤ 255 用 1 字节,否则 2 字节)
索引从1 开始(不是 0)
空字符串'' 是非法值,索引 0 表示错误值或空字符串
NULL允许 NULL 时,NULL 是合法值

演示数据准备

DROP TABLE IF EXISTS employees;

CREATE TABLE employees (
    emp_id INT PRIMARY KEY AUTO_INCREMENT,
    emp_name VARCHAR(20),
    dept VARCHAR(20),
    score DECIMAL(5,2),
    level ENUM('初级', '中级', '高级') DEFAULT '初级'
);

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

当前 employees 表中的完整数据如下:

emp_idemp_namedeptscorelevel
1大翔技术部100高级
2白歌技术部NULL初级

SQL 示例

场景一:插入合法 ENUM 值

当前数据状态:见上文 employees 表完整数据。

执行语句:

INSERT INTO employees (emp_name, dept, score, level) VALUES ('孔蓝', '产品部', 88, '中级');

操作后结果:

SELECT * FROM employees;
emp_idemp_namedeptscorelevel
1大翔技术部100高级
2白歌技术部NULL初级
3孔蓝产品部88中级

结果解读:'中级' 是 ENUM 定义中的合法值,插入成功。ENUM 在插入时会校验值是否在预定义列表中。

场景二:插入非法 ENUM 值的陷阱

当前数据状态:见上文 employees 表完整数据。

执行语句:

-- 严格模式下报错
INSERT INTO employees (emp_name, dept, score, level) VALUES ('赵鸣', '运营部', 76, '专家');

操作后结果:

在 STRICT_TRANS_TABLES 模式下:

ERROR 1265 (01000): Data truncated for column 'level'

在非严格模式下(如 sql_mode = ''):

SELECT * FROM employees WHERE emp_name = '赵鸣';
emp_idemp_namedeptscorelevel
4赵鸣运营部76

结果解读:'专家' 不在 ENUM('初级', '中级', '高级') 列表中。严格模式下直接报错;非严格模式下会插入一个空字符串(内部索引为 0),这是 ENUM 最常见的陷阱——数据被静默截断。

场景三:ENUM 的数值索引特性

当前数据状态:见上文 employees 表完整数据。

执行语句:

-- 按索引插入(不推荐,但合法)
INSERT INTO employees (emp_name, dept, score, level) VALUES ('孙鹤', '技术部', 84, 3);

-- 查询时也可以按索引比较
SELECT emp_name, level FROM employees WHERE level = 3;
SELECT emp_name, level FROM employees WHERE level = '高级';

操作后结果:

SELECT emp_name, level FROM employees WHERE level = '高级';
emp_namelevel
大翔高级
孙鹤高级

结果解读:ENUM 内部存储的是整数索引:1='初级', 2='中级', 3='高级'。因此 level = 3 和 level = '高级' 是等价的。但强烈建议始终使用字符串值,使用数字索引会降低可读性和可维护性。

场景四:ENUM 排序按索引顺序而非字母顺序

当前数据状态:基于上文数据。

执行语句:

SELECT emp_name, level FROM employees ORDER BY level;

操作后结果:

emp_namelevel
白歌初级
孔蓝中级
大翔高级
孙鹤高级

结果解读:ENUM 排序按内部索引顺序(初级=1, 中级=2, 高级=3),而非字符串的字母顺序。这既是优点(按业务等级排序很直观),也是陷阱(如果期望按字母排序会出错)。如需按字母排序,需用 ORDER BY CAST(level AS CHAR)。

场景五:修改 ENUM 定义(添加新成员)

当前数据状态:见上文 employees 表完整数据。

执行语句:

-- 在末尾添加新成员
ALTER TABLE employees MODIFY level ENUM('初级', '中级', '高级', '资深');

-- 插入新成员值
INSERT INTO employees (emp_name, dept, score, level) VALUES ('高英', '运营部', 91, '资深');

操作后结果:

SELECT emp_name, level FROM employees WHERE level = '资深';
emp_namelevel
高英资深

结果解读:ALTER TABLE ... MODIFY 可以扩展 ENUM 的成员列表,但只能在末尾添加。如果需要在中间插入,必须重建整个 ENUM 定义,且已有数据的索引值会变化——这是 ENUM 的最大维护痛点。

重要:修改 ENUM 定义时,已有数据的内部索引不变,但新成员的索引是递增的。如果在中间插入成员,已有数据的索引会重新分配,可能导致数据含义错乱。

常见误区

误区正解
"ENUM 存储的是字符串,和 VARCHAR 一样占空间"不是。ENUM 内部存储 1~2 字节的整数索引,比 VARCHAR 节省大量空间。
"ENUM 可以存储多个值"不能。ENUM 只能存储单个值。需要多选时用 SET 类型。
"ENUM 排序按字符串字母顺序"按内部索引顺序(定义时的顺序),不是字母顺序。
"ENUM 插入非法值会报错"只在严格模式下报错。非严格模式会静默插入空字符串(索引 0)。
"ENUM 成员可以随便增删改"只能在末尾添加。中间插入或删除会改变已有数据的索引含义。
"ENUM 比 TINYINT + 程序映射更好"各有优劣。ENUM 可读性好但维护困难;TINYINT 灵活但需要程序维护映射表。

面试考点

Q:ENUM 和 VARCHAR 的区别?

ENUM 从预定义列表中选单个值,内部存 1~2 字节整数索引,节省空间且自带校验;VARCHAR 存任意字符串,无校验,空间开销大。ENUM 适合状态、等级等有限选项场景。

Q:ENUM 的索引从几开始?插入非法值会怎样?

索引从 1 开始。严格模式下插入非法值报错;非严格模式下插入空字符串(索引 0)。这是常见陷阱,建议始终启用严格模式。

Q:为什么生产环境不推荐使用 ENUM?

  1. 修改成员列表需要 ALTER TABLE,且只能在末尾添加,维护困难;2. 成员顺序影响排序行为和索引值,中间插入会导致数据含义错乱;3. 与程序枚举映射耦合紧密,数据库和代码变更需同步;4. 不如 TINYINT + 程序映射表灵活。适合选项极少且几乎不变的场景(如性别)。

Q:ENUM 和 SET 的区别?

ENUM 单选(内部 1~2 字节),SET 多选(内部 1~8 字节,按位存储)。ENUM 像单选按钮,SET 像复选框。

小结

  • ENUM 用于存储预定义列表中的单个值,内部以整数索引存储,节省空间
  • 索引从 1 开始,排序按索引顺序而非字母顺序
  • 严格模式下插入非法值报错,非严格模式静默插入空字符串
  • 修改成员列表困难,只能在末尾添加,是生产环境的主要痛点
  • 适合选项极少且稳定的场景(如性别、是否),不适合频繁变更的业务状态

下一章引子:ENUM 只能单选,如果需要存储"多选"——比如一个人的多个标签、一个商品的多个属性——就需要 SET 类型。

上一页
BIT 类型
下一页
SET 类型