文档首页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  ...  /  ENUM 类型

13.3.5 ENUM 类型

一个 ENUM 是一个字符串对象,其值从在创建表时在列规范中显式枚举的允许值列表中选择。

有关 ENUM 类型语法和长度限制,请参阅 第 13.3.1 节,“字符串数据类型语法”

ENUM 类型具有以下优点

  • 在列具有有限数量的可能值的场景中,可以实现紧凑的数据存储。您指定为输入值的字符串会自动编码为数字。有关 ENUM 类型的存储要求,请参阅 第 13.7 节,“数据类型存储要求”

  • 可读的查询和输出。这些数字在查询结果中会转换回相应的字符串。

以及以下需要考虑的潜在问题

  • 如果您创建看起来像数字的枚举值,很容易将文字值与它们的内部索引号混淆,如 枚举限制 中所述。

  • ORDER BY 子句中使用 ENUM 列需要格外小心,如 枚举排序 中所述。

创建和使用 ENUM 列

枚举值必须是带引号的字符串文字。例如,您可以使用以下代码创建包含 ENUM 列的表

CREATE TABLE shirts (
    name VARCHAR(40),
    size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
);
INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),
  ('polo shirt','small');
SELECT name, size FROM shirts WHERE size = 'medium';
+---------+--------+
| name    | size   |
+---------+--------+
| t-shirt | medium |
+---------+--------+
UPDATE shirts SET size = 'small' WHERE size = 'large';
COMMIT;

将 100 万行插入到此表中,其值为 'medium',将需要 100 万字节的存储空间,而如果将实际字符串 'medium' 存储在 VARCHAR 列中,则需要 600 万字节的存储空间。

枚举文字的索引值

每个枚举值都有一个索引

  • 列规范中列出的元素将被分配索引号,从 1 开始。

  • 空字符串错误值的索引值为 0。这意味着您可以使用以下 SELECT 语句查找已分配无效 ENUM 值的行

    mysql> SELECT * FROM tbl_name WHERE enum_col=0;
  • NULL 值的索引为 NULL

  • 这里的术语 索引 指的是枚举值列表中的位置。它与表索引无关。

例如,指定为 ENUM('Mercury', 'Venus', 'Earth') 的列可以具有以下所示的任何值。每个值的索引也显示在其中。

索引
NULL NULL
'' 0
'Mercury' 1
'Venus' 2
'Earth' 3

一个 ENUM 列最多可以有 65,535 个不同的元素。

如果您在数字上下文中检索 ENUM 值,则将返回列值的索引。例如,您可以使用以下代码从 ENUM 列中检索数值

mysql> SELECT enum_col+0 FROM tbl_name;

例如 SUM()AVG() 等需要数值参数的函数,如果需要,会将参数强制转换为数字。对于 ENUM 值,索引号将用于计算。

枚举文字的处理

创建表时,会自动从表定义中 ENUM 成员值的尾随空格中删除尾随空格。

检索时,存储到 ENUM 列中的值将使用列定义中使用的字母大小写显示。请注意,ENUM 列可以分配字符集和排序规则。对于二进制或区分大小写的排序规则,在将值分配到列时会考虑字母大小写。

如果您将数字存储到 ENUM 列中,该数字将被视为可能值列表中的索引,并且存储的值是具有该索引的枚举成员。(但是,这 适用于 LOAD DATA,它将所有输入视为字符串。)如果数字值被引用,并且在枚举值列表中没有匹配的字符串,则它仍然被解释为索引。出于这些原因,不建议定义具有看起来像数字的枚举值的 ENUM 列,因为这很容易造成混淆。例如,以下列具有字符串值为 '0''1''2' 的枚举成员,但数字索引值为 123

numbers ENUM('0','1','2')

如果您存储 2,它将被解释为索引值,并将变为 '1'(具有索引 2 的值)。如果您存储 '2',它将与枚举值匹配,因此它将被存储为 '2'。如果您存储 '3',它将不与任何枚举值匹配,因此它将被视为索引,并将变为 '2'(具有索引 3 的值)。

mysql> INSERT INTO t (numbers) VALUES(2),('2'),('3');
mysql> SELECT * FROM t;
+---------+
| numbers |
+---------+
| 1       |
| 2       |
| 2       |
+---------+

要确定 ENUM 列的所有可能值,请使用 SHOW COLUMNS FROM tbl_name LIKE 'enum_col' 并解析输出的 Type 列中的 ENUM 定义。

在 C API 中,ENUM 值将作为字符串返回。有关使用结果集元数据来区分它们与其他字符串的信息,请参阅 C API 基本数据结构

空或 NULL 枚举值

在某些情况下,枚举值也可以是空字符串 ('') 或 NULL

  • 如果您将无效值插入到 ENUM 中(即,列表中不存在的字符串),则将插入空字符串作为特殊的错误值。此字符串可以通过其数字值为 0 的事实与 正常 空字符串区分开来。有关枚举值的数字索引的详细信息,请参阅 枚举文字的索引值

    如果启用了严格 SQL 模式,则尝试插入无效的 ENUM 值会导致错误。

  • 如果 ENUM 列被声明为允许 NULL,则 NULL 值是该列的有效值,并且默认值为 NULL。如果 ENUM 列被声明为 NOT NULL,则其默认值为允许值列表中的第一个元素。

枚举排序

ENUM 值根据其索引号排序,索引号取决于枚举成员在列规范中列出的顺序。例如,对于 ENUM('b', 'a')'b' 排在 'a' 之前。空字符串排在非空字符串之前,NULL 值排在所有其他枚举值之前。

为了防止在 ENUM 列上使用 ORDER BY 子句时出现意外结果,请使用以下技术之一

  • 按字母顺序指定 ENUM 列表。

  • 通过编码 ORDER BY CAST(col AS CHAR)ORDER BY CONCAT(col),确保列按字母顺序排序,而不是按索引号排序。

枚举限制

枚举值不能是表达式,即使是计算结果为字符串值的表达式也不行。

例如,此 CREATE TABLE 语句 无法 工作,因为 CONCAT 函数不能用于构造枚举值

CREATE TABLE sizes (
    size ENUM('small', CONCAT('med','ium'), 'large')
);

您也不能使用用户变量作为枚举值。这两条语句 无法 工作

SET @mysize = 'medium';

CREATE TABLE sizes (
    size ENUM('small', @mysize, 'large')
);

我们强烈建议您 不要 使用数字作为枚举值,因为这并不会节省相对于适当的 TINYINTSMALLINT 类型而言的存储空间,如果您错误地引用了 ENUM 值,很容易将字符串和底层数字值(可能不相同)混淆。如果您确实使用数字作为枚举值,请始终将其括在引号中。如果省略了引号,数字将被视为索引。请参阅 处理枚举文字,了解即使是带引号的数字也可能被错误地用作数字索引值的方式。

定义中的重复值会导致警告,如果启用了严格 SQL 模式,则会导致错误。