15.1.20.6 CHECK 约束
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 中,每种约束类型在每个 schema(数据库)都有自己的命名空间。因此,CHECK
约束名称必须是唯一的 per schema;同一个 schema 中不能共享 CHECK
约束名称。(例外:临时表隐藏非临时表相同名称,可以拥有相同 CHECK
约束名。)
以表名开头生成约束名称有助于确保架构的唯一性,因为架构中的表名也必须是唯一的。
CHECK
条件表达式必须遵守以下规则。如果一个表达式包含不允许的结构,会出现错误。
-
非生成列和生成列都是允许的,除了具有
AUTO_INCREMENT
属性的列和其他表中的列。 -
字面量、确定性内置函数和操作符是允许的。一个函数是确定性的,如果给定同样的数据在表中,多次调用产生相同的结果,不管连接的用户是什么。例如,
CONNECTION_ID()
、CURRENT_USER()
、NOW()
等函数都不是确定性的。 -
存储函数和可加载函数是不允许的。
-
存储程序和函数参数是不允许的。
-
变量(系统变量、用户定义变量和存储程序局部变量)也不允许。
-
子查询不允许。
外键引用操作(ON UPDATE
、ON DELETE
)在CHECK
约束列上是禁止的。同样,CHECK
约束也不能在外键引用操作列上。
CHECK
约束对INSERT
、UPDATE
、REPLACE
、LOAD DATA
和LOAD XML
语句进行评估,如果约束评估为FALSE
,则发生错误。如果发生错误,事务性存储引擎和非事务性存储引擎的更改处理方式不同,同时也取决于是否启用严格SQL模式,详见严格 SQL 模式。
CHECK
约束对INSERT IGNORE
、UPDATE IGNORE
、LOAD DATA ... IGNORE
和LOAD XML ... IGNORE
语句进行评估,如果约束评估为FALSE
,则发出警告,并且跳过任何违反行的插入或更新。
如果约束表达式计算结果的数据类型与声明的列类型不同,会根据 MySQL 通用转换规则隐式强制转换到声明的类型。见第14.3节,“表达式求值中的类型转换”。如果类型转换失败或导致精度损失,会出现错误。
约束表达式计算使用评估时间的 SQL 模式。如果表达式中的任何组件依赖于 SQL 模式,可能在不同的使用场景下产生不同结果,除非在所有使用场景中都保持相同的 SQL 模式。
信息架构CHECK_CONSTRAINTS
表提供了对表定义的CHECK
约束信息。见第28.3.5节,“INFORMATION_SCHEMA CHECK_CONSTRAINTS 表”.