大家好,我是只谈技术不剪发的 Tony 老师。这次我们来介绍一个 MysqL 8.0 增加的新功能:检查约束(CHECK )。
sql 中的检查约束属于完整性约束的一种,可以用于约束表中的某个字段或者一些字段必须满足某个条件。例如用户名必须大写、余额不能小于零等。
我们常见的数据库都实现了检查约束,例如 Oracle、sql Server、Postgresql 以及 sqlite;然而 MysqL 一直以来没有真正实现该功能,直到最新的 MysqL 8.0.16。
MysqL 8.0.15 之前
在 MysqL 8.0.15 以及之前的版本中,虽然 CREATE TABLE 语句允许CHECK (expr)
形式的检查约束语法,但实际上解析之后会忽略该子句。例如
MysqL> select version();
+-----------+
| version() |
+-----------+
| 8.0.15 |
+-----------+
1 row in set (0.00 sec)
MysqL> CREATE TABLE t1
-> (
-> c1 INT CHECK (c1 > 10),
-> c2 INT ,
-> c3 INT CHECK (c3 < 100),
-> CONSTRAINT c2_positive CHECK (c2 > 0),
-> CHECK (c1 > c3)
-> );
Query OK, 0 rows affected (0.33 sec)
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
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
虽然我们在定义时指定了各种 CHECK 选项,但最终的表结构中不包含任何检查约束。这也意味着我们可以插入非法的数据:
MysqL> insert into t1(c1, c2, c3) values(1, -1, 100);
Query OK, 1 row affected (0.06 sec)
如果我们想要在 MysqL 8.0.15 之前实现类似的检查约束,可以使用触发器;或者创建一个包含 WITH CHECK OPTION 选项的视图,然后通过视图插入或修改数据。
MysqL 8.0.16 之后
MysqL 8.0.16 于 2019 年 4 月 25 日发布,终于带来了我们期待已久的 CHECK 约束功能,而且对于所有的存储引擎都有效。CREATE TABLE 语句允许以下形式的 CHECK 约束语法,可以指定列级约束和表级约束:
[CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]
其中,可选的 symbol 参数用于给约束指定一个名称。如果省略该选项,MysqL 将会产生一个以表名开头、加上 _chk_ 以及一个数字编号(1、2、3 …)组成的名字(table_name_chk_n)。约束名称最大长度为 64 个字符,而且区分大小写。
expr 是一个布尔表达式,用于指定约束的条件;表中的每行数据都必须满足 expr 的结果为 TRUE 或者 UNKNowN(NULL)。如果表达式的结果为 FALSE,将会违反约束。
可选的 ENFORCED 子句用于指定是否强制该约束:
- 如果忽略或者指定了 ENFORCED,创建并强制该约束;
- 如果指定了 NOT ENFORCED,创建但是不强制该约束。这也意味着约束不会生效。
CHECK 约束可以在列级指定,也可以在表级指定。
列级检查约束
列级约束只能出现在字段定义之后,而且只能针对该字段进行约束。例如:
MysqL> select version();
+-----------+
| version() |
+-----------+
| 8.0.16 |
+-----------+
1 row in set (0.00 sec)
MysqL> CREATE TABLE t1
-> (
-> c1 INT CHECK (c1 > 10),
-> c2 INT CONSTRAINT c2_positive CHECK (c2 > 0),
-> c3 INT CHECK (c3 < 100)
-> );
Query OK, 0 rows affected (0.04 sec)
MysqL> show create table t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`c1` int DEFAULT NULL,
`c2` int DEFAULT NULL,
`c3` int DEFAULT NULL,
CONSTRAINT `c2_positive` CHECK ((`c2` > 0)),
CONSTRAINT `t1_chk_1` CHECK ((`c1` > 10)),
CONSTRAINT `t1_chk_2` CHECK ((`c3` < 100))
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
其中,字段 c1 和 c3 上的检查约束使用了系统生成的名称;c2 上的检查约束使用了自定义名称。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。