文档首页
MySQL 8.4 参考手册
相关文档 下载本手册

MySQL 8.4 参考手册  /  ...  /  检查约束

15.1.20.6 检查约束

CREATE TABLE 允许所有存储引擎使用表和列 CHECK 约束的核心功能。CREATE TABLE 允许以下 CHECK 约束语法,用于表约束和列约束

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

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

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

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

  • 如果省略或指定为 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 表会隐藏同名的非 TEMPORARY 表,因此它也可以具有相同的 CHECK 约束名称。)

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

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

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

  • 允许使用文字、确定性内置函数和运算符。 如果在表中给出相同的数据,则函数是确定性的,多次调用会产生相同的结果,而与连接的用户无关。 非确定性函数的示例,这些函数不符合此定义:CONNECTION_ID()、CURRENT_USER()、NOW()。

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

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

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

  • 不允许使用子查询。

禁止对外键引用操作(ON UPDATE、ON DELETE)使用 CHECK 约束中的列。 同样,禁止对外键引用操作中使用的列使用 CHECK 约束。

将针对 INSERT、UPDATE、REPLACE、LOAD DATA 和 LOAD XML 语句评估 CHECK 约束,如果约束评估为 FALSE,则会发生错误。 如果发生错误,则已应用的更改的处理方式对于事务性和非事务性存储引擎会有所不同,并且还取决于是否启用了严格 SQL 模式,如严格 SQL 模式中所述。

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

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

注意

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

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