史上最簡單的 MySQL 教程(二十五)「外來鍵」
外來鍵
外來鍵:foreign key
,外面的鍵,即不在自己表中的鍵。如果一張表中有一個非主鍵的欄位指向另外一張表的主鍵,那麼將該欄位稱之為外來鍵。每張表中,可以有多個外來鍵。
新增外來鍵
外來鍵既可以在建立表的時候增加,也可以在建立表之後增加(但是要考慮資料的問題)。
第 1 種:在建立表的時候,增加外來鍵
- 基本語法:
foreign key(外來鍵欄位) + references + 外部表名(主鍵欄位);
執行如下 SQL 語句,進行測試:
-- 建立外來鍵
create table my_foreign1(
id int primary key auto_increment,
name varchar (20) not null comment '學生姓名',
c_id int comment '班級表ID',
-- 增加外來鍵
foreign key(c_id) references class(id)
)charset utf8;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
觀察上圖可知,欄位c_id
的key
顯示為MUL
,表示多個鍵的意思。這是因為外來鍵要求欄位本身是一個索引(普通索引)如果欄位本身沒有索引,外來鍵就會先建立一個索引,然後才建立外來鍵本身。此外,CONSTRAINT
後面的my_foreign_ibfk_1
表示外來鍵的名字。
第 2 種:在建立表之後,增加外來鍵
- 基本語法:
alter table + 表名 + add[constraint + 外來鍵名字] + foreign key(外來鍵欄位) + references + 外部表名(主鍵欄位);
執行如下 SQL 語句,進行測試:
-- 建立外來鍵
create table my_foreign2(
id int primary key auto_increment,
name varchar(20) not null comment '學生姓名',
c_id int comment '班級表ID'
)charset utf8;
-- 增加外來鍵
alter table my_foreign2 add
-- 指定外來鍵名
constraint test_foreign
-- 指定外來鍵欄位
foreign key(c_id)
-- 引用外部表主鍵
references class(id);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
如上圖所示,顯然咱們已經增加外來鍵成功啦!
修改外來鍵 & 刪除外來鍵
外來鍵不能修改,只能先刪除後增加。
- 基本語法:
alter table + 表名 + drop foreign key + 外來鍵名字;
執行如下 SQL 語句,進行測試:
-- 刪除外來鍵
alter table my_foreign1 drop foreign key my_foreign1_ibfk_1;
- 1
- 2
觀察上圖可知,刪除外來鍵不能通過查看錶結構來體現,而是應該通過建立表的語句來檢視。
溫馨提示:符號[]
括起來的內容,表示可選項;符號+
,則表示連線的意思。
外來鍵作用
首先,給出父表和子表的定義:
- 父表,指外來鍵所指向的表;
- 子表,指相對於父表,擁有外來鍵的表。
外來鍵預設的作用有兩個,分別對子表和父表進行約束。
第 1 種:約束子表
在子表進行資料的寫操作(增和改)的時候,如果對應的外來鍵欄位在父表找不到對應的匹配,那麼操作就會失敗。
執行如下 SQL 語句,進行測試:
-- 插入資料,外來鍵欄位在父表不存在
insert into my_foreign2 values(null,'Charies','6');
-- 插入資料,外來鍵欄位在父表存在
insert into my_foreign2 values(null,'Charies','1');
- 1
- 2
- 3
- 4
- 5
如上圖所示,在我們向子表my_foreign2
插入外來鍵欄位為6
的時候,提示插入失敗,原因就是在父表class
中,沒有ID
為6
的記錄。而在我們向子表my_foreign2
插入外來鍵欄位為1
的時候,提示成功,原因就是在父表class
中,有ID
為1
的記錄。
第 2 種:約束父表
在父表進行資料的寫操作(刪和改,且涉及主鍵)的時候,如果對應的主鍵欄位在子表已經被資料引用,那麼操作就會失敗。
執行如下 SQL 語句,進行測試:
-- 更新父表記錄
update class set id = 5 where id = 1;
update class set id = 5 where id = 3;
- 1
- 2
- 3
如上圖所示,在我們修改父表class
中ID
為1
的時候,提示修改失敗,原因就是在子表my_foreign2
中已經引用了該值的主鍵欄位。而在我們修改父表class
中ID
為3
的時候,提示修改成功,原因就是在子表my_foreign2
中並沒有引用該值的主鍵欄位。
外來鍵條件
在我們使用外來鍵的時候,應該遵循如下條件:
- 外來鍵要存在,首先必須保證表的引擎是 InnoDB(預設的儲存引擎),如果不是 InnoDB 儲存引擎,那麼外來鍵可以建立成功,但沒有約束作用;
- 外來鍵欄位的欄位型別(列型別),必須與父表的主鍵型別完全一致;
- 每張表中的外來鍵名稱不能重複;
- 增加外來鍵的欄位,如果資料已經存在,那麼要保證資料與父表中的主鍵對應。
下面以最後一個條件為例,執行如下 SQL 語句,進行測試:
-- 新增資料
insert into my_foreign1 valuse(1,'Gavin',3);
-- 增加外來鍵
alter table my_foreign1 add foreign key(c_id) references class(id);
- 1
- 2
- 3
- 4
- 5
如上圖所示,在新增外來鍵的時候,如果子表中(想要新增外來鍵的欄位)的資料已經存在,而父表中又沒有與子表中(想要新增外來鍵的欄位)的資料相匹配的主鍵的話,那麼操作就會失敗;反之,則會成功。
執行如下 SQL 語句,進行測試:
-- 新增資料
insert into class valuse(3,'PM3.4','A115');
-- 增加外來鍵
alter table my_foreign1 add foreign key(c_id) references class(id);
- 1
- 2
- 3
- 4
- 5
如上圖所示,顯然當父表中存在與子表中(想要新增外來鍵的欄位)的資料相匹配的主鍵的話,增加主鍵的操作就會成功。
外來鍵約束
所謂外來鍵約束,就是指外來鍵的作用。之前所講的外來鍵的作用都是預設的作用,實際上,可以通過對外來鍵的需求,進行定製操作。
外來鍵約束有三種模式,分別為:
district
:嚴格模式(預設),父表不能刪除或更新一個已經被子表資料引用的記錄;cascade
:級聯模式,父表的操作,對應子表關聯的資料也跟著被刪除;set null
:置空模式,父表的操作之後,子表對應的資料(外來鍵欄位)被置空。
在此需要注意:以上三種模式,都是對父表的約束。
- 基本語法:
foreign key(外來鍵欄位) + references + 父表(主鍵欄位) + [on delete + 模式 + on update + 模式];
通常一個合理的做法(約束模式)是:刪除的時候, 子表被置空;更新的時候,子表進行級聯操作。
執行如下 SQL 語句,進行測試:
-- 建立外來鍵,指定模式:刪除置空,更新級聯
create table my_foreign3(
id int primary key auto_increment,
name varchar(20) not null,
c_id int,
-- 增加外來鍵
foreign key(c_id)
-- 引用父表
references class(id)
-- 指定刪除模式
on delete set null
-- 指定更新模式
on update cascade
)charset utf8;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
如上圖所示,在我們指定外來鍵的約束模式之後,通過查看錶的建立語句,可以看到具體的約束語句。
接下來,執行如下 SQL 語句,繼續進行測試:
-- 插入資料
insert into my_foreign3 values(null,'Jobs',1),
(null,'Bill',1),
(null,'Mark',1),
(null,'Swift',2),
(null,'Sellen',1);
- 1
- 2
- 3
- 4
- 5
- 6
如上圖所示,我們向表my_foreign3
中插入了 5 條記錄。接下來,我們就可以測試外來鍵的級聯模式和置空模式啦!呃,對啦,前提是我們需要把與父表class
相關聯的除my_foreign3
之外的其他子表,也就是my_foreign1
和my_foreign2
的外來鍵刪除掉,否則的話,由於這兩個子表的外來鍵使用了嚴格模式,會干擾我們接下來的測試。
在我們刪除表my_foreign1
和my_foreign2
的外來鍵之後,執行如下 SQL 語句,測試級聯模式:
-- 更新父表主鍵
update class set id = 8 where id = 1;
- 1
- 2
執行如下 SQL 語句,測試置空模式:
-- 刪除父表主鍵
delete from class where id = 2;
- 1
- 2
通過以上測試,我們已經驗證了級聯模式和置空模式的效果。其實,在我們進行刪除置空操作的時候,有一個前提,那就是:子表的外來鍵欄位必須允許為空,否則的話,操作是無法成功的。
至此,我們已經把外來鍵的相關操作都演示了一遍。在這裡,我們會發現外來鍵的功能非常強大,能夠進行各種的約束,也正是由於外來鍵這種約束的強大,其降低了開發語言對資料的可控性,因此在實際的開發中,很少使用外來鍵來處理資料。
溫馨提示:符號[]
括起來的內容,表示可選項;符號+
,則表示連線的意思。