CodeGym /課程 /SQL SELF /在建立資料表時建立外鍵

在建立資料表時建立外鍵

SQL SELF
等級 19, 課堂 1
開放

歡迎來到我們課程裡最重要的講座之一!今天要聊聊怎麼在 PostgreSQL 裡建立外鍵。這主題在資料庫設計裡超級關鍵,因為外鍵就像是讓不同資料表之間能夠互相連結的橋樑。如果你覺得自己快要在未來的「SQL 城市」裡迷路了,那就把外鍵想像成連接不同區域的橋吧。

簡單來說,外鍵就是某個資料表裡的一個欄位(或一組欄位),它會參照另一個資料表裡的欄位(通常是主鍵)。

舉例來說,如果你有兩個資料表——students(學生)跟 courses(課程),那 courses 資料表裡的外鍵就可以「指向」某個學生,表示這門課是誰選的。這樣就建立了兩個資料表之間的關聯。

為什麼這很重要?

  1. 外鍵可以幫你確保資料完整性:你不能在一個資料表裡寫入某個東西,如果它在另一個表裡根本不存在。
  2. 它們讓你操作資料更方便。比如說,當你刪除一筆資料時,可以設定自動把相關的資料也一起刪掉。

建立外鍵的語法

在 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);
-- 錯誤:違反外鍵限制

建立外鍵時常見的錯誤

  1. 外鍵沒加索引。PostgreSQL 會自動幫主鍵加索引,但外鍵不會。如果你常常在 WHERE 條件裡用到外鍵,記得自己加個索引。
  2. 建立資料表的順序錯誤。你不能建立一個外鍵去參照還沒存在的資料表。
  3. 忘記加 ON DELETE 或 ON UPDATE 修飾詞。這樣在編輯資料時可能會出現意想不到的狀況。

現在你已經知道怎麼建立外鍵了,這可是打造結構化又一致的資料庫的超強工具。下一堂課我們會更深入聊聊 ON DELETE CASCADE 跟 ON UPDATE RESTRICT 怎麼用來管理關聯資料。

2
任務
SQL SELF, 等級 19, 課堂 1
上鎖
建立一個簡單的「一對多」關聯
建立一個簡單的「一對多」關聯
2
任務
SQL SELF, 等級 19, 課堂 1
上鎖
建立帶有 `ON DELETE CASCADE` 動作的資料表
建立帶有 `ON DELETE CASCADE` 動作的資料表
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION