歡迎來到我們課程裡最重要的講座之一!今天要聊聊怎麼在 PostgreSQL 裡建立外鍵。這主題在資料庫設計裡超級關鍵,因為外鍵就像是讓不同資料表之間能夠互相連結的橋樑。如果你覺得自己快要在未來的「SQL 城市」裡迷路了,那就把外鍵想像成連接不同區域的橋吧。
簡單來說,外鍵就是某個資料表裡的一個欄位(或一組欄位),它會參照另一個資料表裡的欄位(通常是主鍵)。
舉例來說,如果你有兩個資料表——students(學生)跟 courses(課程),那 courses 資料表裡的外鍵就可以「指向」某個學生,表示這門課是誰選的。這樣就建立了兩個資料表之間的關聯。
為什麼這很重要?
- 外鍵可以幫你確保資料完整性:你不能在一個資料表裡寫入某個東西,如果它在另一個表裡根本不存在。
- 它們讓你操作資料更方便。比如說,當你刪除一筆資料時,可以設定自動把相關的資料也一起刪掉。
建立外鍵的語法
在 PostgreSQL 裡建立外鍵很簡單——只要一點 SQL 魔法。基本語法如下:
CREATE TABLE 依賴_資料表 (
欄位_foreign_id DATA_TYPE REFERENCES 父_資料表(欄位_id)
);
我們來深入一點,直接看幾個例子。
範例 1:students 跟 courses 資料表
假設我們想要建立學生跟課程之間的關聯。每一門課都要對應到某個學生。這樣的話,只要執行下面這個 SQL:
CREATE TABLE students (
student_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
student_id INT REFERENCES students(student_id)
);
這裡:
- 在
students資料表裡,我們用PRIMARY KEY來標識每個學生。 - 在
courses資料表裡,student_id欄位就是外鍵FOREIGN KEY,它參照students資料表裡的student_id欄位。
students 資料表
| student_id | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
courses 資料表
| course_id | title | student_id - FOREIGN KEY |
|---|---|---|
| 1 | SQL Basics | 1 |
| 2 | Algorithms | 1 |
| 3 | Data Structures | 2 |
| 4 | Intro to Python | 3 |
重要提醒
當你加上外鍵時,PostgreSQL 會自動建立一個規則,檢查外鍵的值是不是已經存在於指定的資料表裡。如果你試著插入一個錯誤的值,資料庫就會報錯。
實戰應用:students、courses 跟 enrollments 模型
來看一個更複雜的「多對多」關係例子。同一個學生可以選很多課,一門課也可以有很多學生。要建立這種關聯,我們需要一個中介資料表。
CREATE TABLE students (
student_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
title TEXT NOT NULL
);
CREATE TABLE enrollments (
enrollment_id SERIAL PRIMARY KEY,
student_id INT REFERENCES students(student_id), -- 外鍵
course_id INT REFERENCES courses(course_id) -- 外鍵
);
這裡 enrollments 資料表就是用外鍵 student_id 跟 course_id 把 students 跟 courses 連起來。
插入資料
-- 加入學生
INSERT INTO students (name) VALUES ('伊凡 伊凡諾夫'), ('瑪麗亞 斯米爾諾娃');
-- 加入課程
INSERT INTO courses (title) VALUES ('數學'), ('物理');
-- 學生選課
INSERT INTO enrollments (student_id, course_id) VALUES (1, 1), (1, 2), (2, 1);
查詢資料
現在我們可以很輕鬆地查詢某個學生選了哪些課,或是哪門課有哪些學生選:
-- 伊凡 伊凡諾夫選的課程
SELECT c.title
FROM enrollments e
JOIN courses c ON e.course_id = c.course_id
WHERE e.student_id = 1;
-- 選了「數學」這門課的學生
SELECT s.name
FROM enrollments e
JOIN students s ON e.student_id = s.student_id
WHERE e.course_id = 1;
進階功能:ON DELETE 跟 ON UPDATE
外鍵還可以控制當父資料表的資料被修改或刪除時,子資料表要怎麼反應。這時候就要用 ON DELETE 跟 ON UPDATE 修飾詞。主要有這幾種選項:
- CASCADE:父資料表的資料被修改或刪除時,子資料表的相關資料也會自動跟著變動。
- SET NULL:子資料表的外鍵值會被設成
NULL。 - RESTRICT:如果子資料表已經用到這筆資料,就不允許刪除或修改父資料表的資料。
- NO ACTION:其實跟
RESTRICT差不多,只是檢查的時機點不一樣。
範例 2:用 ON DELETE CASCADE
假設我們想要這樣設定:只要從 students 資料表刪除一個學生,courses 資料表裡所有跟這個學生有關的課程也會自動被刪掉。這樣寫:
CREATE TABLE students (
student_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
student_id INT REFERENCES students(student_id) ON DELETE CASCADE
);
現在,如果你從 students 資料表刪除一個學生,所有 跟這個學生有關的 courses 資料表裡的課程也會被刪掉。例如:
INSERT INTO students (name) VALUES ('伊凡 伊凡諾夫');
INSERT INTO courses (title, student_id) VALUES ('數學', 1), ('物理', 1);
-- 刪除學生伊凡諾夫
DELETE FROM students WHERE student_id = 1;
-- courses 資料表現在會是空的,因為所有跟伊凡諾夫有關的課程都被刪掉了
我們會在下一堂課再更詳細地討論這個主題。
使用外鍵時的資料驗證流程
當你建立外鍵時,PostgreSQL 就像一個很嚴格的守門員,每一筆新資料都會檢查。例如:
- 如果你試著插入一筆外鍵值不存在的資料,就會報錯。
- 如果你刪除父資料表裡的資料,而這筆資料已經被其他表參照(又沒用
ON DELETE CASCADE),就會違反資料完整性。
範例:試圖插入不正確的資料
-- 嘗試把課程分配給不存在的學生
INSERT INTO enrollments (student_id, course_id) VALUES (3, 1);
-- 錯誤:違反外鍵限制
建立外鍵時常見的錯誤
- 外鍵沒加索引。PostgreSQL 會自動幫主鍵加索引,但外鍵不會。如果你常常在
WHERE條件裡用到外鍵,記得自己加個索引。 - 建立資料表的順序錯誤。你不能建立一個外鍵去參照還沒存在的資料表。
- 忘記加
ON DELETE或ON UPDATE修飾詞。這樣在編輯資料時可能會出現意想不到的狀況。
現在你已經知道怎麼建立外鍵了,這可是打造結構化又一致的資料庫的超強工具。下一堂課我們會更深入聊聊 ON DELETE CASCADE 跟 ON UPDATE RESTRICT 怎麼用來管理關聯資料。
GO TO FULL VERSION