1、概念:約束是作用於表中欄位上的規則,用於限制儲存在表中的資料
2、目的:保證資料庫中的資料的正確性,有效性和完整性
3、分類
需求1:建立一個表id、name、age、address、stu_num五個欄位。
需求2:id欄位為主鍵,且設定為自動遞增。
需求3:name欄位長度為10個字元並且不能為空。
需求4:age欄位要大於0並且小於150.
需求5:address欄位如果不設,預設為廣州。
需求6:stu_num唯一且不能為空。
mysql> create table stu_table( -> id int primary key auto_increment comment "id主鍵", -> name varchar(10) not null comment "姓名", -> age int check(age>0 && age<150) comment "年齡", -> address varchar(10) default "廣州" comment "地址", -> stu_num int not null unique comment "學號" -> ) comment "學生表"; Query OK, 0 rows affected, 1 warning (0.03 sec)
stu_table的表結構如下
mysql> desc stu_table; +---------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+---------+----------------+ | id | int | NO | PRI | NULL | auto_increment | | name | varchar(10) | NO | | NULL | | | age | int | YES | | NULL | | | address | varchar(10) | YES | | 廣州 | | | stu_num | int | NO | UNI | NULL | | +---------+-------------+------+-----+---------+----------------+ 5 rows in set (0.01 sec)
說明:
mysql> insert into stu_table (name, age, address, stu_num) values ("張三", 18, "深圳",10001); Query OK, 1 row affected (0.00 sec) mysql> select * from stu_table; +----+--------+------+---------+---------+ | id | name | age | address | stu_num | +----+--------+------+---------+---------+ | 1 | 張三 | 18 | 深圳 | 10001 | +----+--------+------+---------+---------+ 1 row in set (0.00 sec)
說明1:各個欄位都複合各個欄位的要求,新增正常沒有問題
mysql> insert into stu_table (name, age, address, stu_num) values ("ABCDEFGHIJK", 18, "深圳",10002); ERROR 1406 (22001): Data too long for column 'name' at row 1
說明2:直接報錯,提示 name data too long 太長了
mysql> insert into stu_table (name, age, address, stu_num) values ("李四", 152, "深圳",10003); ERROR 3819 (HY000): Check constraint 'stu_table_chk_1' is violated.
說明3:這裡提示了一個驗證錯誤
mysql> insert into stu_table (name, age, stu_num) values ("李四", 19,10002); Query OK, 1 row affected (0.01 sec) mysql> select * from stu_table; +----+--------+------+---------+---------+ | id | name | age | address | stu_num | +----+--------+------+---------+---------+ | 1 | 張三 | 18 | 深圳 | 10001 | | 2 | 李四 | 19 | 廣州 | 10002 | +----+--------+------+---------+---------+ 2 rows in set (0.00 sec)
說明4:在上面的insert 語句中只設定了name,age,stu_num三個欄位,所以adderss就自動設定了預設值廣州
mysql> insert into stu_table (name, age, address, stu_num) values ("王五", 21, "上海",10002); ERROR 1062 (23000): Duplicate entry '10002' for key 'stu_table.stu_num'
說明5:提示10002已經重複了
說明1:《學生表》和《輔導員》表示兩張相互獨立的表。
說明2:在《學生表》中的輔導員編號,和《輔導員表》中的輔導員編號是一一對應的
說明3:這種情況下就可以通過輔導員編號這個欄位將《學生表》和《輔導員表》聯絡起來了
說明4:這是輔導員編號欄位,就符合設定為外來鍵的條件
說明5:如果將《學生表》中的輔導員編號欄位設定為外來鍵,則《學生表》為子表,《輔導員表》為父表
說明6:外來鍵在父表中是唯一,不可重複的。
說明1:通過上圖發現《學生表》中的班級id和《班級表》中的班級id也存在一一對應的關係
說明2:班級id也符合設定外來鍵的標準。
說明3:例如:輔導員編號,班級id都符合外來鍵的設定標準,所以一個表中可以有多個外來鍵,但是每個外來鍵對應不同的表
說明1:在《學生表》班級評級欄位和《班級考核與平級對照表》中的班級平級欄位也存在著關係。
說明2:但是這個班級評級欄位就不存在外來鍵的特徵,因為班級評級在《班級考核與評級對照表》中不是惟一的。
說明3:在子表中的四星,對應父表中有三種情況這樣就會出現子表中的四星到底對應父表的哪一個四星的情況。
1、原始資料:student表結構及其資料
mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | 1 | 98 | | 2 | stu2 | 1 | 88 | | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.00 sec)
2、原始資料:teacher表結構及其資料
mysql> select * from teacher; +------------+--------------+ | id | teacher_name | +------------+--------------+ | 1 | 張三 | | 2 | 李四 | | 3 | 王五 | +------------+--------------+ 3 rows in set (0.00 sec)
3、新增外來鍵的語法
alter table 表名 add constraint 外來鍵名稱 foreign key (外來鍵欄位名) references 父表 (父表欄位)on update 更新行為 on delete 刪除行為
說明1:alter table 是DML語法,修改表的意思,在之前的文章中已經介紹過
說明2:add constraint 是新增約束的意思
說明3:foreign key 是外來鍵約束的關鍵字
說明4:references 後面跟上父表和父表中欄位
4、需求:給student表中的teacher_id設定為teacher表的外來鍵,並且對應id欄位的資料
mysql> alter table student add constraint fk_teacher foreign key (teacher_id) references teacher (id); Query OK, 6 rows affected (0.22 sec) Records: 6 Duplicates: 0 Warnings: 0
說明1:外來鍵一旦設定成功,將會保持子表和父表的資料一致性和完整性。
說明2:這個時候,如果我刪除《teacher》表中的id=1的張三老師,就會出錯,因為,如果張三在《teacher》表中刪除了,則在《student》中的輔導員編號這列資料就找不到對應的值
說明3:從而這樣就破壞了資料的完整性和一致性
mysql> delete from teacher where id=1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`mysql_test`.`student`, CONSTRAINT `fk_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`))
說明1:這個時候就會提示,不能刪除或者修改父表中的資料,因為有外來鍵存在
5、外來鍵資料的更新和刪除行為
6、重新建立《student》和《teacher》表並新增外來鍵
mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | 1 | 98 | | 2 | stu2 | 1 | 88 | | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.00 sec) mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 1 | 張三 | | 2 | 李四 | | 3 | 王五 | +----+--------------+ 3 rows in set (0.00 sec) mysql> alter table student add constraint fk_teacher foreign key (teacher_id) references teacher(id) on update cascade on delete cascade; Query OK, 6 rows affected (0.05 sec) Records: 6 Duplicates: 0 Warnings: 0
7、驗證cascade級聯行為
驗證1:我修改《teacher》表中id=1的資料改為id=4
mysql> update teacher set id=4 where id=1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 2 | 李四 | | 3 | 王五 | | 4 | 張三 | +----+--------------+ 3 rows in set (0.01 sec) mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | 4 | 98 | | 2 | stu2 | 4 | 88 | | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.00 sec)
說明1:這個時候我們會發現,當我修改了《teacher》表中輔導員編號的id欄位是,在《student》表中teacher_id 原本等於1的也都改為了4,這就是cascade的作用
驗證2:cascade的刪除行為
mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 2 | 李四 | | 3 | 王五 | +----+--------------+ 2 rows in set (0.00 sec) mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 4 rows in set (0.00 sec)
說明2:和更新一樣,cascade的刪除也是級聯的。
8、驗證set null的更新和刪除行為
需求1:同樣先刪除《student》和《teacher》表然後重新建立新的表,重新建立外來鍵約束測試
mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 1 | 張三 | | 2 | 李四 | | 3 | 王五 | +----+--------------+ 3 rows in set (0.00 sec) mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | 1 | 98 | | 2 | stu2 | 1 | 88 | | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.00 sec) mysql> alter table student add constraint fk_teacher foreign key (teacher_id) references teacher(id) on update set null on delete set null; Query OK, 6 rows affected (0.04 sec) Records: 6 Duplicates: 0 Warnings: 0
驗證1:更新《teacher》表中id=1的資料,改為id=4
mysql> update teacher set id=4 where id=1; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 2 | 李四 | | 3 | 王五 | | 4 | 張三 | +----+--------------+ 3 rows in set (0.00 sec) mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | NULL | 98 | | 2 | stu2 | NULL | 88 | | 3 | stu3 | 2 | 79 | | 4 | stu4 | 2 | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.01 sec)
說明1:對應更新的資料都改為了null
驗證2:刪除《teacher》表中id=2的資料
mysql> delete from teacher where id = 2; Query OK, 1 row affected (0.01 sec) mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 3 | 王五 | | 4 | 張三 | +----+--------------+ 2 rows in set (0.00 sec) mysql> select * from student; +----+----------+------------+-------+ | id | stu_name | teacher_id | score | +----+----------+------------+-------+ | 1 | stu1 | NULL | 98 | | 2 | stu2 | NULL | 88 | | 3 | stu3 | NULL | 79 | | 4 | stu4 | NULL | 97 | | 5 | stu5 | 3 | 93 | | 6 | stu6 | 3 | 86 | +----+----------+------------+-------+ 6 rows in set (0.00 sec)
說明1:當刪除資料的時候,子表中對應的外來鍵資料也會變成了null
1、刪除外來鍵的語法
alter table 表名 drop foreign key 外來鍵名稱;
mysql> alter table student drop foreign key fk_teacher; Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0
2、刪除外來鍵後,資料一致性和完整性的驗證
mysql> delete from teacher where id=1; Query OK, 1 row affected (0.01 sec) mysql> select * from teacher; +----+--------------+ | id | teacher_name | +----+--------------+ | 2 | 李四 | | 3 | 王五 | +----+--------------+ 2 rows in set (0.00 sec)
說明1:這個時候就可以在《teacher》表中刪除id=1的張三老師了,但是這樣《student》表和《teacher》表的資料的一致性就破壞了