社區投稿 | MySQL 8.0.16 開始支持 check 完整性

原創: 蔣樂興html


做者簡介python

蔣樂興,MySQL DBA,擅長 python 和 SQL ,目前維護着github的兩個開源項目:mysqltools 、dbmc以及獨立博客:https://www.sqlpy.commysql

 

一直以來MySQL都只實現了實體完整性、域完整性、引用完整性、惟一鍵約束。git

惟獨 check 完整性遲遲沒有到來,MySQL 8.0.16(2019-04-25 GA) 版本爲這個畫上了句號。github

 

1、沒有 check 完整性約束會怎樣

一、沒有 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

 

2、看用 check 如何解決

一、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

相關文章
相關標籤/搜索