1. 程式人生 > >史上最簡單的 MySQL 教程(二十五)「外來鍵」

史上最簡單的 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

foreign1

觀察上圖可知,欄位c_idkey顯示為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

foreign2

如上圖所示,顯然咱們已經增加外來鍵成功啦!

修改外來鍵 & 刪除外來鍵

外來鍵不能修改,只能先刪除後增加。

  • 基本語法alter table + 表名 + drop foreign key + 外來鍵名字;

執行如下 SQL 語句,進行測試:

-- 刪除外來鍵
alter table my_foreign1 drop foreign key my_foreign1_ibfk_1;
  • 1
  • 2

foreign3

觀察上圖可知,刪除外來鍵不能通過查看錶結構來體現,而是應該通過建立表的語句來檢視。

溫馨提示:符號[]括起來的內容,表示可選項;符號+,則表示連線的意思。

外來鍵作用

首先,給出父表和子表的定義:

  • 父表,指外來鍵所指向的表;
  • 子表,指相對於父表,擁有外來鍵的表。

外來鍵預設的作用有兩個,分別對子表和父表進行約束。

第 1 種:約束子表

在子表進行資料的寫操作(增和改)的時候,如果對應的外來鍵欄位在父表找不到對應的匹配,那麼操作就會失敗。

執行如下 SQL 語句,進行測試:

-- 插入資料,外來鍵欄位在父表不存在
insert into my_foreign2 values(null,'Charies','6'); 

-- 插入資料,外來鍵欄位在父表存在
insert into my_foreign2 values(null,'Charies','1'); 
  • 1
  • 2
  • 3
  • 4
  • 5

foreign4

如上圖所示,在我們向子表my_foreign2插入外來鍵欄位為6的時候,提示插入失敗,原因就是在父表class中,沒有ID6的記錄。而在我們向子表my_foreign2插入外來鍵欄位為1的時候,提示成功,原因就是在父表class中,有ID1的記錄。

第 2 種:約束父表

在父表進行資料的寫操作(刪和改,且涉及主鍵)的時候,如果對應的主鍵欄位在子表已經被資料引用,那麼操作就會失敗。

執行如下 SQL 語句,進行測試:

-- 更新父表記錄
update class set id = 5 where id = 1;
update class set id = 5 where id = 3;
  • 1
  • 2
  • 3

foreign5

如上圖所示,在我們修改父表classID1的時候,提示修改失敗,原因就是在子表my_foreign2中已經引用了該值的主鍵欄位。而在我們修改父表classID3的時候,提示修改成功,原因就是在子表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

foreign6

如上圖所示,在新增外來鍵的時候,如果子表中(想要新增外來鍵的欄位)的資料已經存在,而父表中又沒有與子表中(想要新增外來鍵的欄位)的資料相匹配的主鍵的話,那麼操作就會失敗;反之,則會成功。

執行如下 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

foreign7

如上圖所示,顯然當父表中存在與子表中(想要新增外來鍵的欄位)的資料相匹配的主鍵的話,增加主鍵的操作就會成功。

外來鍵約束

所謂外來鍵約束,就是指外來鍵的作用。之前所講的外來鍵的作用都是預設的作用,實際上,可以通過對外來鍵的需求,進行定製操作。

外來鍵約束有三種模式,分別為:

  • 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

foreign8

如上圖所示,在我們指定外來鍵的約束模式之後,通過查看錶的建立語句,可以看到具體的約束語句。

接下來,執行如下 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

foreign9

如上圖所示,我們向表my_foreign3中插入了 5 條記錄。接下來,我們就可以測試外來鍵的級聯模式和置空模式啦!呃,對啦,前提是我們需要把與父表class相關聯的除my_foreign3之外的其他子表,也就是my_foreign1my_foreign2的外來鍵刪除掉,否則的話,由於這兩個子表的外來鍵使用了嚴格模式,會干擾我們接下來的測試。

在我們刪除表my_foreign1my_foreign2的外來鍵之後,執行如下 SQL 語句,測試級聯模式:

-- 更新父表主鍵
update class set id = 8 where id = 1;
  • 1
  • 2

foreign10

執行如下 SQL 語句,測試置空模式:

-- 刪除父表主鍵
delete from class where id = 2;
  • 1
  • 2

foreign11

通過以上測試,我們已經驗證了級聯模式和置空模式的效果。其實,在我們進行刪除置空操作的時候,有一個前提,那就是:子表的外來鍵欄位必須允許為空,否則的話,操作是無法成功的

至此,我們已經把外來鍵的相關操作都演示了一遍。在這裡,我們會發現外來鍵的功能非常強大,能夠進行各種的約束,也正是由於外來鍵這種約束的強大,其降低了開發語言對資料的可控性,因此在實際的開發中,很少使用外來鍵來處理資料。

溫馨提示:符號[]括起來的內容,表示可選項;符號+,則表示連線的意思。