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

15.1.20.6 检查约束

CREATE TABLE 允许表和列检查约束的核心功能,对所有存储引擎有效。CREATE TABLE 允许以下检查约束语法,对于表约束和列约束:

[CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]

可选的 符号 指定约束的名称。如果省略,MySQL 将从表名、literal _chk_ 和序号(1、2、3、...)生成名称。约束名称的最大长度为 64 个字符。它们区分大小写,但不区分重音。

expr 指定约束条件作为布尔表达式,该表达式必须对每行表数据评估为 TRUEUNKNOWN(对于 NULL 值)。如果条件评估为 FALSE,则约束失败并发生违规。违规的影响取决于执行的语句,如本节后面所述。

可选的执行子句指示约束是否执行:

  • 如果省略或指定为 ENFORCED,则创建并执行约束。

  • 如果指定为 NOT ENFORCED,则创建但不执行约束。

检查约束可以指定为表约束或列约束:

  • 表约束不在列定义中出现,可以引用任何表列或多个列。前向引用允许引用在表定义中后面出现的列。

  • 列约束出现在列定义中,只能引用该列。

考虑以下表定义:

CREATE TABLE t1
(
  CHECK (c1 <> c2),
  c1 INT CHECK (c1 > 10),
  c2 INT CONSTRAINT c2_positive CHECK (c2 > 0),
  c3 INT CHECK (c3 < 100),
  CONSTRAINT c1_nonzero CHECK (c1 <> 0),
  CHECK (c1 > c3)
);

定义包括表约束和列约束,以命名和未命名格式:

  • 第一个约束是一个表约束:它出现在任何列定义之外,因此可以(并且可以)引用多个表列。该约束包含对尚未定义的列的前向引用。没有指定约束名称,因此 MySQL 生成一个名称。

  • 接下来的三个约束是列约束:每个出现在列定义中,因此只能引用该列。一个约束被明确命名。MySQL 为其他两个生成名称。

  • 最后两个约束是表约束。一个被明确命名。MySQL 为另一个生成名称。

如前所述,MySQL 为任何未指定名称的检查约束生成名称。要查看前面的表定义生成的名称,请使用 SHOW CREATE TABLE

mysql> SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `c1` int(11) DEFAULT NULL,
  `c2` int(11) DEFAULT NULL,
  `c3` int(11) DEFAULT NULL,
  CONSTRAINT `c1_nonzero` CHECK ((`c1` <> 0)),
  CONSTRAINT `c2_positive` CHECK ((`c2` > 0)),
  CONSTRAINT `t1_chk_1` CHECK ((`c1` <> `c2`)),
  CONSTRAINT `t1_chk_2` CHECK ((`c1` > 10)),
  CONSTRAINT `t1_chk_3` CHECK ((`c3` < 100)),
  CONSTRAINT `t1_chk_4` CHECK ((`c1` > `c3`))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

SQL 标准规定所有类型的约束(主键、唯一索引、外键、检查)属于同一个命名空间。在 MySQL 中,每种约束类型在每个模式(数据库)中都有其自己的命名空间。因此,CHECK 约束名称必须在每个模式中唯一;同一个模式中的两个表不能共享同一个 CHECK 约束名称。(例外:一个 TEMPORARY 表隐藏了一个非 TEMPORARY 表同名的表,因此它也可以拥有相同的 CHECK 约束名称。)

以表名开头的生成约束名称有助于确保模式唯一性,因为表名也必须在模式中唯一。

CHECK 条件表达式必须遵守以下规则。如果表达式包含不允许的构造,将发生错误。

  • 非生成列和生成列均允许,除了具有 AUTO_INCREMENT 属性的列和其他表中的列。

  • 文字、确定性内置函数和运算符均允许。一个函数是确定性的,如果给定相同的表数据,多次调用将产生相同的结果,不管连接的用户是谁。例如,不确定性的函数包括:CONNECTION_ID()CURRENT_USER()NOW()

  • 存储函数和可加载函数不允许。

  • 存储过程和函数参数不允许。

  • 变量(系统变量、用户定义变量和存储程序局部变量)不允许。

  • 子查询不允许。

外键参照操作(ON UPDATEON DELETE)在 CHECK 约束中使用的列上是禁止的。同样,CHECK 约束也不能在外键参照操作中使用的列上。

CHECK 约束在 INSERTUPDATEREPLACELOAD DATALOAD XML 语句中被评估,如果约束评估结果为 FALSE,将发生错误。如果发生错误,已经应用的更改处理方式取决于存储引擎是否事务性,以及是否启用严格 SQL 模式,如 严格 SQL 模式 中所述。

检查 约束在 INSERT IGNORE, UPDATE IGNORE, LOAD DATA ... IGNORELOAD XML ... IGNORE 语句中被评估,如果约束评估结果为 FALSE,将出现警告,并跳过该行的插入或更新。

如果约束表达式的评估结果的数据类型与声明的列类型不同,将根据 MySQL 的通常类型转换规则进行隐式强制转换。请参阅 第 14.3 节,“表达式评估中的类型转换”。如果类型转换失败或导致精度损失,将出现错误。

Note

约束表达式的评估使用当前的 SQL 模式。如果表达式的任何组件依赖于 SQL 模式,那么在不同的表使用中可能会出现不同的结果,除非在所有使用中 SQL 模式都是相同的。

信息模式 CHECK_CONSTRAINTS 表提供了关于表上的 CHECK 约束的信息。请参阅 第 28.3.5 节,“信息模式 CHECK_CONSTRAINTS 表”