上一回我們介紹了如何透過程式碼對資料表進行插入(INSERT)、刪除(DELETE)及更新(UPDATE)。這一回我們將來介紹外鍵(Foreign Key)。
假如我們要新增供應商的欄位,供應商可能包含了名字、電話及地址等資訊,如果我們單純的將所有欄位都直接設置在同一張表單上(如下圖),在資料筆數不多的情況下可能還好,但隨著資料數增長,供應商的名字和電話號碼可能會一直重複出現,而每次輸入資料都得重新輸入一次,修改也必須一筆一筆手動修改。假設有1000筆資料,其中有500筆資料的供應商都是開拓食品,如果他今天改了電話號碼,我們就得手動修改500筆資料,這必然是件非常耗時、沒效率的作法。

所以就輪到我們這次的主角——外鍵(Foreign Key)登場了,外鍵的作用:
- 建立關聯:將兩張資料表連結在一起,例如關聯供應商和材料庫存的資料表。
- 確保資料一致性:防止出現孤兒紀錄,比如不能在材料庫存的資料表中隨便填一個不存在的供應商。
- 維護資料完整性:外鍵可以防止刪除或更新父表中的資料,而導致子表中存在無效的參考資料,從而保證資料的完整性。
就像身分證字號一樣,當你在銀行開戶時,銀行會記錄你的身分證字號來確認你的身分。這個身分證字號就像外鍵,它必須是真實存在的,而且能夠連結到你的個人資料,當你的個人資料有任何修改都能夠即時反映。
補充說明:其實上述內容就是資料庫正規化中的第二正規化(2NF),所有非主鍵欄位都完全依賴於主鍵,比如材料庫存中的欄位都必須依賴於ID,而不會有供應商電話依賴於供應商的情形(避免部分相依)。
創建供應商的資料表
接下來,我們使用DB Browser打開上回的Ingredient.db,並點選建立資料表:
資料表命名為Supplier,欄位如下:
- ID─供應商的ID,整數型態、主鍵、自動增值。
- Name─供應商的名稱,字串型態。
- Phone─供應商的電話,字串型態。
確認無誤後點選「OK」進行建立,確認建立完成後記得寫入變更。

接下來我們先直接在DB Browser建立兩筆供應商資料,分別是開拓食品和黃隆食品,電話分別為(02)1234-5678、(02)8888-9999:

建立外鍵
再來回到資料庫結構的索引標籤,對ingredient點選修改表格:

新增一個欄位,命名為Supplier_ID,並在後方外鍵的欄位中設定關聯Supplier的ID欄位,並在後方輸入ON DELETE RESTRICT ON UPDATE CASCADE:

創建完成後,再到瀏覽資料的索引標籤中,為我們原先的三筆資料加上Supplier_ID,分別為1、1、2:

補充一下:
- ON DELETE RESTRICT:不能刪除還有在供應庫存的供應商。
- ON UPDATE CASCADE:如果供應商ID改變,庫存表中的供應商ID會自動更新。
除了CASCADE和RESTRICT外,還有NO ACTION(SQLite預設)、SET NULL,實際差異日後會再補充。
測試查詢資料
現在我們回到Python,使用以下程式碼查詢包括供應商名稱、電話欄位在內的資料:
import sqlite3
con = sqlite3.connect("Ingredient.db")
cur = con.cursor()
cur.execute('''
SELECT i.Name, i.Amount, i.Unit, s.Name, s.Phone
FROM ingredient i
INNER JOIN Supplier s ON i.Supplier_ID = s.ID
;''')
rows = cur.fetchall()
for row in rows:
print(row)
查詢外鍵關聯表的其他欄位,主要透過 JOIN 來實現,SQLite中又分成INNER JOIN、LEFT JOIN,差異如下:
- INNER JOIN:只返回有關聯的記錄,預設的JOIN為此種。
- LEFT JOIN:返回左表所有記錄,右表沒有對應則為 NULL。
補充:在其他關聯式資料庫中還有RIGHT JOIN等其他種類,但我們在這裡只以SQLite有支援的為主。
i和s則分別是ingredient和Supplier兩張資料表的別名(alias),可自行設置,僅是方便辨認及使用。
程式碼執行後會得到以下結果:

這樣代表我們可以透過ingredient中的Supplier_ID欄位查找到供應商的名稱、電話,
而之後要修改供應商的電話或名稱,僅需修改Supplier這張資料表中的資料即可,比如開拓食品的電話號碼要進行修改,只要到Supplier中修改開拓食品的電話號碼就好(1筆),以方才提到的例子來說,要修改的數量瞬間從500筆降到1筆,效率大幅提高。
下一步
這一回我們介紹了外鍵的原理,並且為ingredient資料表設置了關聯到供應商的外鍵,並且使用程式碼進行查詢。不知道各位是否覺得輸出結果不太容易讀懂?因為完全沒有對應的欄位,僅有一條一條的資料內容,就好像讀書沒有標題和回目一樣。於是下一回我們除了介紹如何在Python中插入有外鍵的資料外,我們還會在介紹一個常見的套件─pandas中的DataFrame。