前面我們介紹了主鍵(Primary Key),它幫助我們唯一識別每一筆資料。
有了主鍵之後,我們終於可以介紹另一個很重要的限制:外部鍵(Foreign Key)。
什麼是外部鍵?為什麼需要它?我們來看一個例子。
為什麼需要外部鍵
假設我們有一個「結婚表」:
| 人物 | 結婚對象 |
|---|---|
| David | Emily |
| Emily | David |
| Frank | NULL |
| Grace | Henry |
我們來檢查每一筆資料的「結婚對象」是否合理:
第一筆:David 的結婚對象是 Emily
Emily 有出現在人物欄位嗎?有,第二筆的人物就是 Emily。所以這筆資料沒問題 ✓
第二筆:Emily 的結婚對象是 David
David 有出現在人物欄位嗎?有,第一筆的人物就是 David。所以這筆資料沒問題 ✓
第三筆:Frank 的結婚對象是 NULL
NULL 代表「沒有值」,表示 Frank 沒有結婚。這也沒問題 ✓
第四筆:Grace 的結婚對象是 Henry
Henry 有出現在人物欄位嗎?我們來看看:David、Emily、Frank、Grace… 沒有 Henry!
Grace 說她的結婚對象是 Henry,但 Henry 根本不在這張表的人物欄位裡。這代表 Grace 的結婚對象是一個「不存在的人」。
這筆資料是有問題的。我們不應該允許這種情況發生。
那怎麼辦?
我們希望資料庫能幫我們擋掉這種情況:如果人物欄位裡沒有這個人,結婚對象就不能填這個人。
這種「一個欄位的值必須參考另一個欄位」的限制,就叫做外部鍵(Foreign Key)。
設定外部鍵之後,資料庫會自動幫你檢查:如果你試著填入一個不存在的值,資料庫就會拒絕寫入,不讓這筆資料進到資料庫裡。
設定外部鍵
當你設定外部鍵的時候,一定要說明:這個欄位要參考誰?
這個「參考的對象」叫做 Reference(參考)。
以結婚表為例:
| 人物(PK) | 結婚對象(FK) |
|---|---|
| David | Emily |
| Emily | David |
| Frank | NULL |
| Grace | Henry |
這裡的「結婚對象」欄位設定了外部鍵,它的 Reference 是「人物」欄位。
這表示:
- 結婚對象填的值,必須是人物欄位裡出現過的值
- 如果人物欄位裡沒有 Henry,那結婚對象就不能填 Henry
違反外部鍵限制會怎樣
如果你試著在「結婚對象」填入一個人物欄位裡不存在的人(像 Henry),會發生什麼事?
我們來看一下這個情況:
| 人物(PK) | 結婚對象(FK) |
|---|---|
| David | Emily |
| Emily | David |
| Frank | NULL |
| Grace | Henry |
Grace 的結婚對象是 Henry,但人物欄位裡沒有 Henry。這筆資料違反了外部鍵的限制。
當你試著寫入這筆資料時,資料庫會怎麼處理?
有兩種常見的處理方式:
- 拒絕寫入:資料庫直接擋掉這筆資料,不讓你寫進去。你會看到一個錯誤訊息,告訴你「違反外部鍵限制」。
- 設為空值:資料庫讓你寫入,但把結婚對象自動改成 NULL。
大多數情況下是第一種:直接擋掉。
為什麼?因為如果資料庫自動把值改成 NULL,你可能不知道原本填的值有問題。直接報錯可以讓你馬上發現問題,確保資料的一致性。
外部鍵通常搭配 NOT NULL
在結婚表的例子裡,結婚對象可以是 NULL(像 Frank 沒有結婚)。這是合理的,因為不是每個人都有結婚。
但有些情況下,外部鍵欄位不應該是空值。
例如,假設你有一張「訂單表」:
| 訂單 ID(PK) | 商品名稱 | 所屬會員(FK) |
|---|---|---|
| 1 | 鍵盤 | U001 |
| 2 | 滑鼠 | U002 |
| 3 | 螢幕 | NULL |
第三筆訂單的「所屬會員」是 NULL。這代表什麼?
這筆訂單是誰下的?不知道。沒有會員,怎麼出貨?怎麼收款?這筆資料根本沒有意義。
所以在訂單表裡,「所屬會員」應該要加上 NOT NULL 限制,確保每筆訂單都有對應的會員。
要不要加上 NOT NULL,取決於這個欄位在業務邏輯上是否允許空值:
- 結婚對象:可以是 NULL(沒結婚是正常的)
- 訂單的所屬會員:不應該是 NULL(每筆訂單一定要有人下單)
外部鍵通常指向主鍵
外部鍵的 Reference(參考對象)可以是任何欄位嗎?
技術上可以,但絕大多數情況下,外部鍵都會指向主鍵(Primary Key)。
為什麼?
回想一下結婚表的例子:
| 人物(PK) | 結婚對象(FK) |
|---|---|
| David | Emily |
| Emily | David |
結婚對象的 Reference 是「人物」欄位,而人物欄位是這張表的主鍵。
主鍵有三個條件:不能重複、不應該改變、不能是空值。
如果外部鍵指向的欄位不是主鍵,可能會發生什麼事?
- 如果那個欄位會重複:結婚對象填 David,但有兩個 David,到底是指哪一個?
- 如果那個欄位會改變:結婚對象填 David,結果 David 改名叫 Kevin,關聯就斷掉了
- 如果那個欄位是空值:結婚對象填的值根本不存在
這跟我們在 PRIMARY KEY 那篇說的「用姓名關聯」的問題一模一樣。
那正確的做法是什麼?
如果人物欄位不是主鍵,我們應該另外建立一個 ID 欄位當主鍵,然後讓結婚對象指向這個 ID:
| 人物 ID(PK) | 人物姓名 | 結婚對象(FK) |
|---|---|---|
| 1 | David | 2 |
| 2 | Emily | 1 |
| 3 | Frank | NULL |
現在結婚對象填的是 ID,不是姓名。就算 David 改名叫 Kevin,結婚對象填的還是 2,關聯不會斷掉。
所以,外部鍵應該指向主鍵,才能確保外部鍵真正指向一筆特定的、不會變的資料。
FOREIGN KEY 重點整理
- 什麼是外部鍵:一個欄位的值必須參考另一個表單的欄位
- 為什麼需要:確保關聯的資料真的存在,避免指向不存在的資料
- Reference:設定外部鍵時,必須指定參考的對象是哪個表單的哪個欄位
- 違反限制:通常會拒絕寫入,確保資料一致性
- 搭配 NOT NULL:大多數情況下,外部鍵欄位不應該是空值
- 指向主鍵:外部鍵通常指向另一張表的主鍵,確保指向特定的資料
到目前為止,我們學了四種欄位限制:
- UNIQUE:確保欄位的值不重複
- NOT NULL:確保欄位一定要有值
- PRIMARY KEY:確保可以唯一識別每一筆資料(包含 UNIQUE + NOT NULL)
- FOREIGN KEY:確保欄位的值必須參考另一個表單的欄位