Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 Reference Manual  /  ...  /  The ENUM Type

13.3.5 ENUM 类型

ENUM 是在表创建时通过列规范指定的字符串对象,值来自于明确枚举的允许值列表。

请查看第13.3.1节,“字符串数据类型语法”,了解ENUM 类型的语法和长度限制。

ENUM 类型具有以下优点:

  • 在列有有限可能值的情况下,紧凑的数据存储。您指定的输入值将自动编码为数字。查看第13.7节,“数据类型存储要求”,了解ENUM 类型的存储要求。

  • 可读性查询和输出。数字将在查询结果中翻译回对应的字符串。

并且需要考虑以下潜在问题:

  • 如果您枚举值看起来像数字,很容易混淆字面值与内部索引号,如枚举限制中所解释的那样。

  • ORDER BY 子句中使用 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'值需要1万字节的存储空间,而如果你在VARCHAR列中存储实际字符串'medium'则需要6万字节。

每个枚举值都有索引:

  • 列指定的元素被分配索引号,从1开始。

  • 空字符串错误值的索引是0。这意味着你可以使用以下SELECT语句来找到分配无效ENUM值的行:

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

  • 在这里,index 指的是枚举值的位置,与表索引无关。

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

Value Index
NULL NULL
'' 0
'Mercury' 1
'Venus' 2
'Earth' 3

枚举类型的列最多可以有65,535个唯一元素。

如果在数值上下文中检索ENUM值,列值的索引将被返回。例如,可以像这样从ENUM列中检索数值:

mysql> SELECT enum_col+0 FROM tbl_name;

期望数字参数的函数,如SUM()AVG(),如果必要将参数转换为数字。对于ENUM值,索引号将被用于计算。

在创建表时,枚举值的末尾空格将自动被删除。

当从ENUM列中检索值时,使用了该列定义中的字母大小写。注意ENUM列可以指定字符集和排序规则。在二进制或区分大小写的排序规则下,字母大小写在将值分配给列时被考虑。

如果将数字存储到ENUM列中,该数字将被视为可能值的索引,并将该索引对应的枚举成员存储。如果输入的数字被引用,仍然会被解释为索引,如果没有匹配的字符串在枚举值列表中。因此,不建议定义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在某些情况下:

  • 如果您将无效的值插入到一个ENUM(即不在允许值列表中的字符串),那么空字符串被插入作为特殊错误值。这一字符串可以通过它的数字值 0 来区分与正常的空字符串。见枚举字面量索引值了解枚举值的数字索引详细信息。

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

  • 如果将ENUM列声明为允许NULL,那么NULL值是该列的有效值,默认值也是NULL。如果将ENUM列声明为NOT NULL,那么默认值就是列表中的第一个元素。

ENUM值根据枚举成员在列定义中的顺序进行排序,例如'b'排在'a'前面对于ENUM('b', 'a')。空字符串排在非空字符串之前,NULL值排在所有枚举值之前。

使用ORDER BY子句对ENUM列进行排序时,防止意外结果,可以采取以下方法:

  • 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 模式时报错。