Documentation Home

13.1.20.6 检查约束

在 MySQL 8.0.16 之前,CREATE TABLE只允许以下有限版本的表CHECK约束语法,它被解析并被忽略:

CHECK (expr)

从 MySQL 8.0.16 开始,允许所有存储引擎 CREATE TABLE 使用表和列约束的核心功能 。对于表约束和列约束,允许使用以下约束语法: CHECKCREATE TABLECHECK

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

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

expr将约束条件指定为布尔表达式,该表达式的计算结果必须 为表的每一行的TRUEUNKNOWN(对于 值)。NULL如果条件的计算结果为FALSE,则它失败并发生约束冲突。违规的影响取决于正在执行的语句,如本节后面所述。

可选的 enforcement 子句指示约束是否被强制执行:

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

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

约束被指定CHECK为表约束或列约束:

  • 表约束不出现在列定义中,可以引用任何表列。允许对表定义中稍后出现的列进行前向引用。

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

考虑这个表定义:

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 为任何 CHECK未指定的约束生成一个名称。要查看为前面的表定义生成的名称,请使用 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的非表,因此它也可以具有相同的约束名称。) TEMPORARYCHECK

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

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

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

  • 允许使用文字、确定性内置函数和运算符。一个函数是确定性的,如果给定表中的相同数据,多次调用产生相同的结果,独立于连接的用户。不确定且未通过此定义的函数示例:CONNECTION_ID(), CURRENT_USER(), NOW()

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

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

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

  • 不允许子查询。

约束中使用的列禁止使用 外键引用操作 ( ON UPDATE, )。同样, 在外键引用操作中使用的列也禁止约束。 ON DELETECHECKCHECK

CHECKINSERTUPDATEREPLACELOAD DATALOAD XML语句评估约束,如果约束评估为 ,则会发生错误FALSE。如果发生错误,事务和非事务存储引擎对已应用更改的处理会有所不同,并且还取决于严格 SQL 模式是否生效,如 严格 SQL 模式中所述。

CHECK对 、 、 和 语句评估约束,如果约束评估为INSERT IGNORE, 则会出现警告。跳过任何违规行的插入或更新。 UPDATE IGNORELOAD DATA ... IGNORELOAD XML ... IGNOREFALSE

如果约束表达式的计算结果为不同于声明的列类型的数据类型,则根据通常的 MySQL 类型转换规则对声明的类型进行隐式强制转换。请参阅第 12.3 节,“表达式计算中的类型转换”。如果类型转换失败或导致精度损失,则会发生错误。

笔记

约束表达式求值使用求值时有效的 SQL 模式。如果表达式的任何部分依赖于 SQL 模式,则表的不同使用可能会产生不同的结果,除非 SQL 模式在所有使用过程中都相同。

INFORMATION_SCHEMA.CHECK_CONSTRAINTS 表提供有关CHECK 在表上定义的约束的信息。请参阅 第 26.3.5 节,“INFORMATION_SCHEMA CHECK_CONSTRAINTS 表”