CREATE TABLE
允许表和列检查约束的核心功能,对所有存储引擎有效。CREATE TABLE
允许以下检查约束语法,对于表约束和列约束:
[CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]
可选的 符号
指定约束的名称。如果省略,MySQL 将从表名、literal _chk_
和序号(1、2、3、...)生成名称。约束名称的最大长度为 64 个字符。它们区分大小写,但不区分重音。
expr
指定约束条件作为布尔表达式,该表达式必须对每行表数据评估为 TRUE
或 UNKNOWN
(对于 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 UPDATE
、ON DELETE
)在 CHECK
约束中使用的列上是禁止的。同样,CHECK
约束也不能在外键参照操作中使用的列上。
CHECK
约束在 INSERT
、UPDATE
、REPLACE
、LOAD DATA
和 LOAD XML
语句中被评估,如果约束评估结果为 FALSE
,将发生错误。如果发生错误,已经应用的更改处理方式取决于存储引擎是否事务性,以及是否启用严格 SQL 模式,如 严格 SQL 模式 中所述。
检查
约束在 INSERT IGNORE
, UPDATE IGNORE
, LOAD DATA ... IGNORE
和 LOAD XML ... IGNORE
语句中被评估,如果约束评估结果为 FALSE
,将出现警告,并跳过该行的插入或更新。
如果约束表达式的评估结果的数据类型与声明的列类型不同,将根据 MySQL 的通常类型转换规则进行隐式强制转换。请参阅 第 14.3 节,“表达式评估中的类型转换”。如果类型转换失败或导致精度损失,将出现错误。
约束表达式的评估使用当前的 SQL 模式。如果表达式的任何组件依赖于 SQL 模式,那么在不同的表使用中可能会出现不同的结果,除非在所有使用中 SQL 模式都是相同的。
信息模式 CHECK_CONSTRAINTS
表提供了关于表上的 CHECK
约束的信息。请参阅 第 28.3.5 节,“信息模式 CHECK_CONSTRAINTS 表”。