原創: 蔣樂興html
做者簡介python
蔣樂興,MySQL DBA,擅長 python 和 SQL ,目前維護着github的兩個開源項目:mysqltools 、dbmc以及獨立博客:https://www.sqlpy.com。mysql
一直以來MySQL都只實現了實體完整性、域完整性、引用完整性、惟一鍵約束。git
惟獨 check 完整性遲遲沒有到來,MySQL 8.0.16(2019-04-25 GA) 版本爲這個畫上了句號。github
一、沒有 check 完整性約束可能會影響到數據的質量。sql
-- 建立一個 person 表來保存名字,年齡這個兩個基本信息 CREATE TABLE person ( NAME VARCHAR ( 16 ), age INT ); -- 這種狀況下能夠插入一個年齡爲 -32 的行,負的年齡明顯是沒有意義的 INSERT INTO person ( NAME, age ) VALUE ( '張三歲',- 32 ); select * from person; +-----------+------+ | name | age | +-----------+------+ | 張三歲 | -32 | +-----------+------+ 1 row in set (0.00 sec)
二、若是單單只是不能容忍負值,咱們能夠換一種非負整數類型來克服一下。spa
-- 先刪除以前的 person 定義 drop table if exists person; Query OK, 0 rows affected (0.01 sec) -- 建立一個新的 person 表 create table if not exists person(name varchar(16),age int unsigned); Query OK, 0 rows affected (0.01 sec) -- 聲明的時候說明了 age 只能是正數,因此插入負數就會報錯 insert into person(name,age) value('張三歲',-32); ERROR 1264 (22003): Out of range value for column 'age' at row 1
上面的這種解決方案其實就是經過域完整性來實現的數據驗證,域完整性的能力仍是有邊界的。code
好比說,要求age必定要18歲之上它是作不到的,而這種需求正是check完整性大顯身手的地方。htm
一、MySQL 8.0.16+版本, check 完整性解決age要大於18的問題。ci
select @@version; +-----------+ | @@version | +-----------+ | 8.0.16 | +-----------+ 1 row in set (0.00 sec) -- 先刪除以前定義的表 drop table if exists person; Query OK, 0 rows affected (0.01 sec) -- 建立新的表,並對 age 列進行驗證,要求它必定要大於 18 create table if not exists person( name varchar(16), age int, constraint ck_person_001 check (age > 18) -- 加一個 check 約束條件 ); Query OK, 0 rows affected (0.02 sec) -- 查看錶的定義 show create table person; +--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | person | CREATE TABLE `person` ( `name` varchar(16) DEFAULT NULL, `age` int(11) DEFAULT NULL, CONSTRAINT `ck_person_001` CHECK ((`age` > 18)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci | +--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) -- 插入的數據若是不能經過 check 約束就會報錯 insert into person(name,age) value('張三歲',-32); ERROR 3819 (HY000): Check constraint 'ck_person_001' is violated. insert into person(name,age) values('張三歲',17); ERROR 3819 (HY000): Check constraint 'ck_person_001' is violated. insert into person(name,age) values('張三歲',19); Query OK, 1 row affected (0.01 sec)
二、MySQL 8.0.16 如下版本的 MySQL 會怎樣?
select @@version; +-----------+ | @@version | +-----------+ | 8.0.15 | +-----------+ 1 row in set (0.00 sec) drop table if exists person; Query OK, 0 rows affected (0.00 sec) create table if not exists person( name varchar(16), age int, constraint ck_person_001 check (age > 18) -- 加一個 check 約束條件 ); Query OK, 0 rows affected (0.01 sec) -- 能夠看到在低版本下 check 約束被直接無視了,也就是說低版本是沒有 check 約束的 show create table person; +--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | person | CREATE TABLE `person` ( `name` varchar(16) COLLATE utf8mb4_general_ci DEFAULT NULL, `age` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci | +--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) -- insert into person(name,age) value('張三歲',-32); Query OK, 1 row affected (0.00 sec)
能夠看到在 MySQL 8.0.16 如下的版本中,check直接被忽略。
新版本在CHECK Constraints功能上的完善提升了對非法或不合理數據寫入的控制能力。
除了以上示例中的列約束以外,CHECK Constraints還支持表約束。
想要了解更多關於CHECK Constraints 的詳細語法規則和注意事項,請參考MySQL官網文檔
https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html