在 MySQL 8.0.16 之前,CREATE TABLE 只允许以下有限功能版本的表 CHECK 约束语法,它被解析并忽略:
1. CHECK (expr)
从 MySQL 8.0.16 开始,CREATE TABLE 支持表和列 CHECK 约束的核心功能,适用于所有存储引擎。对于表约束和列约束,CREATE TABLE 允许以下 CHECK 约束语法:
1. [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]
可选项 symbol 指定约束的名称。如果省略,MySQL 将从表名、字面量 chk 和一个序数(1,2,3…)生成一个名称。约束名称的最大长度为64个字符。它们区分大小写,但不区分腔调。
expr 将约束条件指定为布尔表达式,对于表的每一行,该表达式的值必须为 TRUE 或 UNKNOWN (对于 NULL 值)。如果条件的计算结果为 FALSE,则失败并违反了约束。违规的影响取决于所执行的语句,本节稍后将对此进行描述。
可选强制条款指示是否强制约束:
● 如果省略或指定 ENFORCED,则创建并强制约束。
● 如果指定为 NOT ENFORCED,则创建约束但不强制执行。
CHECK 约束指定为表约束或列约束:
● 表约束不出现在列定义中,可以引用任何表列。允许对表定义后面出现的列进行前向引用。
● 列约束出现在列定义中,并且只能引用该列。
考虑这个表的定义:
1. CREATE TABLE t1
2. (
3. CHECK (c1 <> c2),
4. c1 INT CHECK (c1 > 10),
5. c2 INT CONSTRAINT c2_positive CHECK (c2 > 0),
6. c3 INT CHECK (c3 < 100),
7. CONSTRAINT c1_nonzero CHECK (c1 <> 0),
8. CHECK (c1 > c3)
9. );
定义包括命名格式和未命名格式的表约束和列约束:
● 第一个约束是表约束:它发生在任何列定义之外,因此它可以(而且确实)引用多个表列。此约束包含对尚未定义的列的前向引用。没有指定约束名称,因此MySQL会生成一个名称。
● 接下来的三个约束是列约束:每个约束都出现在列定义中,因此只能引用被定义的列。其中一个约束被显式地命名。MySQL 为其他两个约束生成名称。
● 最后两个约束是表约束。其中一个是显式命名的。MySQL 为另一个生成名称。
如前所述,MySQL 为没有指定名称的 CHECK 约束生成一个名称。要查看为上表定义生成的名称,请使用 SHOW CREATE TABLE 语句:
1. mysql> SHOW CREATE TABLE t1\G
2. *************************** 1. row ***************************
3. Table: t1
4. Create Table: CREATE TABLE `t1` (
5. `c1` int(11) DEFAULT NULL,
6. `c2` int(11) DEFAULT NULL,
7. `c3` int(11) DEFAULT NULL,
8. CONSTRAINT `c1_nonzero` CHECK ((`c1` <> 0)),
9. CONSTRAINT `c2_positive` CHECK ((`c2` > 0)),
10. CONSTRAINT `t1_chk_1` CHECK ((`c1` <> `c2`)),
11. CONSTRAINT `t1_chk_2` CHECK ((`c1` > 10)),
12. CONSTRAINT `t1_chk_3` CHECK ((`c3` < 100)),
13. CONSTRAINT `t1_chk_4` CHECK ((`c1` > `c3`))
14. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
SQL标准指定所有类型的约束(主键、惟一索引、外键、检查)都属于同一个名称空间。在MySQL中,每个模式(数据库)的每个约束类型都有自己的名称空间。因此,每个模式的 CHECK 约束名称必须是唯一的;同一模式中的两个表不能共享 CHECK 约束名称。(例外:临时表隐藏了同名的非临时表,因此它也可以有相同的 CHECK 约束名称。)
以表名为开头生成的约束名有助于确保模式惟一性,因为表名在模式中也必须是惟一的。
CHECK 条件表达式必须遵守以下规则。如果表达式包含不允许的构造,则会发生错误。
● 允许非生成列和生成列,但具有 AUTO_INCREMENT 属性的列和其他表中的列除外。
● 允许使用字面量、确定性内置函数和操作符。对于表中相同的数据,多次调用确定性函数产生相同的结果,而不依赖于所连接的用户。结果不确定且未通过此定义的函数示例: CONNECTION_ID()、CURRENT_USER() 和 NOW()。
● 不允许使用存储函数和用户定义函数。
● 不允许使用存储过程和函数参数。
● 不允许使用变量(系统变量、用户定义变量和存储程序局部变量)。
● 不允许使用子查询。
在 CHECK 约束中使用的列上禁止外键引用操作(ON UPDATE, ON DELETE)。同样,在外键引用操作中使用的列上禁止 CHECK 约束。
CHECK 约束将针对 INSERT、UPDATE、REPLACE、LOAD DATA 和 LOAD XML 语句进行评估,如果约束的评估结果为 FALSE,则会出现错误。如果发生错误,事务性和非事务性存储引擎对已经应用的更改的处理是不同的,还取决于是否处于严格SQL模式中。
CHECK 约束将针对 INSERT IGNORE,UPDATE IGNORE,LOAD DATA ... IGNORE 和 LOAD XML ... IGNORE 语句进行评估 ,如果约束的评估结果为 FALSE,则会出现警告。将跳过任何违规行的插入或更新。
如果约束表达式要计算的数据类型与声明的列类型不同,则会根据通常的 MySQL 类型转换规则对声明的列类型进行隐式强制转换。如果类型转换失败或导致精度丢失,则会发生错误。
注意
约束表达式计算在计算时使用有效的SQL模式。如果表达式的任何组件依赖于SQL模式,则表的使用可能产生不同的结果,除非SQL模式在所有使用期间是相同的。
官方地址:
https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html