外鍵
外鍵的用途是確保數據的完整性。它通常包括以下幾種:
1 實體完整性,確保每個實體是唯一的(通過主鍵來實施)
2 域完整性,確保屬性值只從一套特定可選的集合里選擇
3 關聯完整性,確保每個外鍵或是NULL(如果允許的話)或含有與相關主鍵值相配的值
1.什么是外鍵約束
與主鍵約束不同,創建外鍵約束不會自動創建對應的索引。 但是由于以下原因,對外鍵手動創建索引通常是有用的:
- 當在查詢中組合相關表中的數據時,經常在聯接條件中使用外鍵列,方法是將一個表的外鍵約束中的一列或多列與另一個表中的主鍵列或唯一鍵列匹配。 索引使 數據庫引擎 可以在外鍵表中快速查找相關數據。 但是,創建此索引并不是必需的。 即使沒有對兩個相關表定義主鍵或外鍵約束,也可以對來自這兩個表中的數據進行組合,但兩個表間的外鍵關系說明已用其鍵作為條件對其進行了優化,以便組合到查詢中。
- 對主鍵約束的更改可由相關表中的外鍵約束檢查。
外鍵約束(foreign key)就是表與表之間的某種約定的關系,由于這種關系的存在,我們能夠讓表與表之間的數據,更加的完整,關連性更強。
關于數據表的完整性和關連性,可以舉個例子
有二張表,一張是用戶表,一張是訂單表:
1.如果我刪除了用戶表里的用戶,那么訂單表里面跟這個用戶有關的數據,就成了無頭數據了,不完整了。
2.如果我在訂單表里面,隨便插入了一條數據,這個訂單在用戶表里面,沒有與之對應的用戶。這樣數據也不完整了。
如果有外鍵的話,就方便多了,可以不讓用戶刪除數據,或者刪除用戶的話,通過外鍵同樣刪除訂單表里面的數據,這樣也能讓數據完整。
通過外鍵約束,每次插入或更新數據表時,都會檢查數據的完整性。
2.創建外鍵約束
2.1 方法一:通過create table創建外鍵
語法:
1
2
3
4
5
6
7
|
create table 數據表名稱( ..., [ CONSTRAINT [約束名稱]] FOREIGN KEY [外鍵字段] REFERENCES [外鍵表名](外鍵字段,外鍵字段2…..) [ ON DELETE CASCADE ] [ ON UPDATE CASCADE ] ) |
參數的解釋:
RESTRICT: 拒絕對父表的刪除或更新操作。
CASCADE: 從父表刪除或更新且自動刪除或更新子表中匹配的行。ON DELETE CASCADE和ON UPDATE CASCADE都可用
注意:on update cascade是級聯更新的意思,on delete cascade是級聯刪除的意思,意思就是說當你更新或刪除主鍵表,那外鍵表也會跟隨一起更新或刪除。
精簡化后的語法:
1
|
foreign key 當前表的字段 references 外部表名 (關聯的字段) type=innodb |
2.1.1 插入測試數據
例子:我們創建一個數據庫,包含用戶信息表和訂單表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
MariaDB [book]> create database market; # 創建market數據庫 Query OK, 1 row affected (0.00 sec) MariaDB [book]> use market; # 使用market數據庫 Database changed MariaDB [market]> create table userprofile(id int (11) not null auto_increment, name varchar (50) not null default '' , sex int (1) not null default '0' , primary key (id))ENGINE=innodb; # 創建userprofile數據表,指定使用innodb引擎 Query OK, 0 rows affected (0.07 sec) MariaDB [market]> create table user_order(o_id int (11) auto_increment, u_id int (11) default '0' , username varchar (50), money int (11), primary key (o_id), index (u_id), foreign key order_f_key(u_id) references userprofile(id) on delete cascade on update cascade ); # 創建user_order數據表,同時為user_order表的u_id字段做外鍵約束,綁定userprofile表的id字段 Query OK, 0 rows affected (0.04 sec) MariaDB [market]> insert into userprofile( name ,sex) values ( 'HA' ,1),( 'LB' ,2),( 'HPC' ,1); # 向userprofile數據表插入三條記錄 Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 MariaDB [market]> select * from userprofile; # 查詢userprofile數據表的所有記錄 + ----+------+-----+ | id | name | sex | + ----+------+-----+ | 1 | HA | 1 | | 2 | LB | 2 | | 3 | HPC | 1 | + ----+------+-----+ 3 rows in set (0.00 sec) MariaDB [market]> insert into user_order(u_id,username,money) values (1, 'HA' ,234),(2, 'LB' ,146),(3, 'HPC' ,256); # 向user_order數據表插入三條記錄 Query OK, 3 rows affected (0.02 sec) Records: 3 Duplicates: 0 Warnings: 0 MariaDB [market]> select * from user_order; # 查詢user_order數據表的所有記錄 + ------+------+----------+-------+ | o_id | u_id | username | money | + ------+------+----------+-------+ | 1 | 1 | HA | 234 | | 2 | 2 | LB | 146 | | 3 | 3 | HPC | 256 | + ------+------+----------+-------+ 3 rows in set (0.00 sec) MariaDB [market]> select id, name ,sex,money,o_id from userprofile,user_order where id=u_id; # 聯表查詢 + ----+------+-----+-------+------+ | id | name | sex | money | o_id | + ----+------+-----+-------+------+ | 1 | HA | 1 | 234 | 1 | | 2 | LB | 2 | 146 | 2 | | 3 | HPC | 1 | 256 | 3 | + ----+------+-----+-------+------+ 3 rows in set (0.03 sec) |
2.1.2 測試級聯刪除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
MariaDB [market]> delete from userprofile where id=1; # 刪除 user 表中id為1的數據 Query OK, 1 row affected (0.01 sec) MariaDB [market]> select id, name ,sex,money,o_id from userprofile,user_order where id=u_id; + ----+------+-----+-------+------+ | id | name | sex | money | o_id | + ----+------+-----+-------+------+ | 2 | LB | 2 | 146 | 2 | | 3 | HPC | 1 | 256 | 3 | + ----+------+-----+-------+------+ 2 rows in set (0.00 sec) MariaDB [market]> select * from user_order; # 查看 order 表的數據 + ------+------+----------+-------+ | o_id | u_id | username | money | + ------+------+----------+-------+ | 2 | 2 | LB | 146 | | 3 | 3 | HPC | 256 | + ------+------+----------+-------+ 3 rows in set (0.00 sec) |
2.1.3 測試級聯更新
更新數據之前的狀態
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
MariaDB [market]> select * from userprofile; # 查看userprofile表的數據 + ----+------+-----+ | id | name | sex | + ----+------+-----+ | 2 | LB | 2 | | 3 | HPC | 1 | + ----+------+-----+ 3 rows in set (0.00 sec) MariaDB [market]> select * from user_order; # 查看 order 表的數據 + ------+------+----------+-------+ | o_id | u_id | username | money | + ------+------+----------+-------+ | 2 | 2 | LB | 146 | | 3 | 3 | HPC | 256 | + ------+------+----------+-------+ 3 rows in set (0.00 sec) |
更新數據
1
2
3
|
MariaDB [market]> update userprofile set id=6 where id=2; # 把userprofile數據表中id為2的用戶改為id為6 Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0 |
更新數據后的狀態
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
MariaDB [market]> select id, name ,sex,money,o_id from userprofile,user_order where id=u_id; # 聯表查詢,可以看出表中已經沒有id為2的用戶了 + ----+------+-----+-------+------+ | id | name | sex | money | o_id | + ----+------+-----+-------+------+ | 6 | LB | 2 | 146 | 2 | | 3 | HPC | 1 | 256 | 3 | + ----+------+-----+-------+------+ 2 rows in set (0.00 sec) MariaDB [market]> select * from userprofile; # 查看userprofile表的數據,id只剩下3和6 + ----+------+-----+ | id | name | sex | + ----+------+-----+ | 3 | HPC | 1 | | 6 | LB | 2 | + ----+------+-----+ 2 rows in set (0.00 sec) MariaDB [market]> select * from user_order; # 查看user_order表的數據,u_id也改為6 + ------+------+----------+-------+ | o_id | u_id | username | money | + ------+------+----------+-------+ | 2 | 6 | LB | 146 | | 3 | 3 | HPC | 256 | + ------+------+----------+-------+ 2 rows in set (0.00 sec) |
2.1.4 測試數據完整性
1
2
|
MariaDB [market]> insert into user_order(u_id,username,money) values (5, "XJ" ,345); # 單獨向user_order數據表中插入數據,插入數據失敗 ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`market`.`user_order`, CONSTRAINT `user_order_ibfk_1` FOREIGN KEY (`u_id`) REFERENCES `userprofile` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) |
在上面的例子中,user_order表的外鍵約束,user_order表受userprofile表的約束
在user_order里面插入一條數據u_id為5用戶,在userprofile表里面根本沒有,所以插入數據失敗
先向userprofile表中插入記錄,再向user_order表中插入記錄就可以了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
MariaDB [market]> insert into userprofile values (5, "XJ" ,1); # 先向userprofile數據表中插入id為5的記錄,插入數據成功 Query OK, 1 row affected (0.01 sec) MariaDB [market]> insert into user_order(u_id,username,money) values (5, "XJ" ,345); # 再向user_order數據表中插入數據,成功 Query OK, 1 row affected (0.00 sec) MariaDB [market]> select * from userprofile; # 查詢userprofile數據表中的所有記錄 + ----+------+-----+ | id | name | sex | + ----+------+-----+ | 3 | HPC | 1 | | 5 | XJ | 1 | | 6 | LB | 2 | + ----+------+-----+ 3 rows in set (0.00 sec) MariaDB [market]> select * from user_order; # 查詢user_order數據表中的所有記錄 + ------+------+----------+-------+ | o_id | u_id | username | money | + ------+------+----------+-------+ | 2 | 6 | LB | 146 | | 3 | 3 | HPC | 256 | | 5 | 5 | XJ | 345 | + ------+------+----------+-------+ 3 rows in set (0.01 sec) |
2.2 方法二:通過alter table創建外鍵和級聯更新,級聯刪除
語法:
1
2
3
4
5
|
alter table 數據表名稱 add [ constraint [約束名稱] ] foreign key (外鍵字段,..) references 數據表(參照字段,...) [ on update cascade | set null | no action ] [ on delete cascade | set null | no action ] ) |
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
MariaDB [market]> create table user_order1(o_id int (11) auto_increment,u_id int (11) default "0" ,username varchar (50),money int (11), primary key (o_id), index (u_id)); # 創建user_order1數據表,創建表時不使用外鍵約束 Query OK, 0 rows affected (0.11 sec) MariaDB [market]> show create table user_order1; # 查看user_order1數據表的創建信息,沒有外鍵約束 + -------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | + -------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | user_order1 | CREATE TABLE `user_order1` ( `o_id` int (11) NOT NULL AUTO_INCREMENT, `u_id` int (11) DEFAULT '0' , `username` varchar (50) COLLATE utf8_unicode_ci DEFAULT NULL , `money` int (11) DEFAULT NULL , PRIMARY KEY (`o_id`), KEY `u_id` (`u_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE =utf8_unicode_ci | + -------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.01 sec) MariaDB [market]> alter table user_order1 add foreign key (u_id) references userprofile(id) on delete cascade on update cascade ; # 使用 alter 修改user_order1數據表,為user_order1數據表添加外鍵約束 Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [market]> show create table user_order1; # 查看user_order1數據表的創建信息,已經添加了外鍵約束 + -------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | + -------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | user_order1 | CREATE TABLE `user_order1` ( `o_id` int (11) NOT NULL AUTO_INCREMENT, `u_id` int (11) DEFAULT '0' , `username` varchar (50) COLLATE utf8_unicode_ci DEFAULT NULL , `money` int (11) DEFAULT NULL , PRIMARY KEY (`o_id`), KEY `u_id` (`u_id`), CONSTRAINT `user_order1_ibfk_1` FOREIGN KEY (`u_id`) REFERENCES `userprofile` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE =utf8_unicode_ci | + -------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) |
3.刪除外鍵
語法
1
|
alter table 數據表名稱 drop foreign key 約束(外鍵)名稱 |
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
MariaDB [market]> show create table user_order1; # 查看user_order1數據表的創建信息,包含外鍵約束 + -------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | + -------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | user_order1 | CREATE TABLE `user_order1` ( `o_id` int (11) NOT NULL AUTO_INCREMENT, `u_id` int (11) DEFAULT '0' , `username` varchar (50) COLLATE utf8_unicode_ci DEFAULT NULL , `money` int (11) DEFAULT NULL , PRIMARY KEY (`o_id`), KEY `u_id` (`u_id`), CONSTRAINT `user_order1_ibfk_1` FOREIGN KEY (`u_id`) REFERENCES `userprofile` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE =utf8_unicode_ci | + -------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) MariaDB [market]> alter table user_order1 drop foreign key user_order1_ibfk_1; # 為user_order1數據表刪除外鍵約束,外鍵名稱必須與從`show create table user_order1`語句中查到的相同 Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [market]> show create table user_order1; # 查看user_order1數據表的創建信息,外鍵約束已經被刪除了 + -------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | + -------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | user_order1 | CREATE TABLE `user_order1` ( `o_id` int (11) NOT NULL AUTO_INCREMENT, `u_id` int (11) DEFAULT '0' , `username` varchar (50) COLLATE utf8_unicode_ci DEFAULT NULL , `money` int (11) DEFAULT NULL , PRIMARY KEY (`o_id`), KEY `u_id` (`u_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE =utf8_unicode_ci | + -------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) |
4.使用外鍵約束的條件
要想外鍵創建成功,必須滿足以下4個條件:
1、確保參照的表和字段存在。
2、組成外鍵的字段被索引。
3、必須使用type指定存儲引擎為:innodb.
4、外鍵字段和關聯字段,數據類型必須一致。
5.使用外鍵約束需要的注意事項
1.on delete cascade on update cascade 添加級聯刪除和更新:
2.確保參照的表userprofile中id字段存在。
3.確保組成外鍵的字段u_id被索引
4.必須使用type指定存儲引擎為:innodb。
5.外鍵字段和關聯字段,數據類型必須一致。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:http://www.cnblogs.com/renpingsheng/p/9579603.html