Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

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

13.3.5 枚举类型

枚举是一个字符串对象,其值来自于在表创建时在列规范中明确枚举的许可值。

请参阅 第 13.3.1 节,“字符串数据类型语法”,了解 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' 的 600 万字节。

枚举文字的索引值

每个枚举值都有一个索引:

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

  • 空字符串错误值的索引值为 0。这意味着您可以使用以下 SELECT 语句来查找其中插入了无效 ENUM 值的行:

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

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

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

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

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

如果您在数字上下文中检索枚举值,将返回列值的索引。例如,您可以像这样检索枚举列的数字值:

mysql> SELECT enum_col+0 FROM tbl_name;

函数,如 SUM()AVG(),期望一个数字参数,如果必要,将将参数强制转换为数字。对于枚举值,将使用索引号在计算中。

处理枚举文字

尾随空格将自动从 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' 并解析输出中的 ENUM 定义。

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

空或 NULL 枚举值

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

  • 如果您将无效值插入到 ENUM 中(即,不在许可值列表中的字符串),则将插入空字符串作为特殊错误值。该字符串可以通过其数字值为 0 来区分于“正常”的空字符串。有关枚举值的数字索引的详细信息,请参阅 Index Values for Enumeration Literals

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

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

枚举排序

ENUM 值根据其索引号排序,该索引号取决于列规范中枚举成员的顺序。例如,'b' 排序在 'a' 之前对于 ENUM('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 模式,则引发错误。