CodeGym /課程 /SQL SELF /用中介表來建構 MANY-TO-MANY 關聯

用中介表來建構 MANY-TO-MANY 關聯

SQL SELF
等級 19 , 課堂 4
開放

「多對多」關聯就是一個資料表裡的一筆資料可以跟另一個資料表的多筆資料有關聯,反過來也一樣。舉例來說: - 一個學生(在 students 表)可以選修多門課(在 courses 表)。 - 一門課也可以有很多學生選修。

問題來了,這種關聯如果直接存會很麻煩。所以我們會用到 中介表 來存這些關聯。

生活中的例子

想像一下,你有一個學生表跟一個課程表。如果你想在每個表裡加一個欄位來存所有關聯的資料,場面會超混亂:

  • students 表裡,你得存學生選了哪些課。那要怎麼存?用逗號分隔?還是用陣列?查詢起來超麻煩。
  • courses 表裡,你得存有哪些學生選這門課,這更讓人頭痛。

所以正確的做法是:建立第三個表,專門存學生跟課程之間的關聯。

中介表:我們的救星!

中介表(有時候也叫關聯表)解決了所有問題。它會有 兩個外鍵

  • 一個外鍵指向 students 表。
  • 一個外鍵指向 courses 表。

這個表裡的每一筆資料,就是一個學生跟一門課的關聯。

建立「多對多」關聯的資料表

來實作一下!這裡是學生跟課程之間關聯的資料表建立方式:

步驟 1:建立 students

這是我們的學生表。這裡會存學生的唯一 ID 跟名字。

CREATE TABLE students (
    student_id SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);
  • student_id — 學生的唯一識別碼(自動遞增,感謝 SERIAL!)。
  • name — 學生名字。

步驟 2:建立 courses

現在來建立課程表。這裡會存課程的唯一 ID 跟名稱。

CREATE TABLE courses (
    course_id SERIAL PRIMARY KEY,
    title TEXT NOT NULL
);
  • course_id — 課程的唯一識別碼。
  • title — 課程名稱。

步驟 3:建立中介表 enrollments

現在來建立我們的魔法關聯表。它有兩個欄位,每個都是外鍵,分別指向對應的表。

CREATE TABLE enrollments (
    student_id INT REFERENCES students(student_id),
    course_id INT REFERENCES courses(course_id),
    PRIMARY KEY (student_id, course_id)
);

來拆解一下結構:

  • student_id — 外鍵,指向 students 表的 student_id
  • course_id — 外鍵,指向 courses 表的 course_id
  • PRIMARY KEY (student_id, course_id) — 主鍵是這兩個外鍵的組合,這樣每個關聯都不會重複。

插入資料

來加點資料測試一下怎麼運作。

步驟 1:新增學生

INSERT INTO students (name) VALUES
('Alice'),
('Bob'),
('Charlie');

結果:

student_id name
1 Alice
2 Bob
3 Charlie

步驟 2:新增課程

INSERT INTO courses (title) VALUES
('Mathematics'),
('History'),
('Biology');

結果:

course_id title
1 Mathematics
2 History
3 Biology

步驟 3:新增 enrollments 的資料

現在來讓學生選課。比如說:

  • Alice 選了 MathematicsHistory
  • Bob 只選了 Biology
  • Charlie 三門課都選了。
INSERT INTO enrollments (student_id, course_id) VALUES
(1, 1), -- Alice 選 Mathematics
(1, 2), -- Alice 選 History
(2, 3), -- Bob 選 Biology
(3, 1), -- Charlie 選 Mathematics
(3, 2), -- Charlie 選 History
(3, 3); -- Charlie 選 Biology

結果:

student_id course_id
1 1
1 2
2 3
3 1
3 2
3 3

「多對多」關聯的查詢

現在有資料了,來看看怎麼查!

怎麼查一個學生選了哪些課?

比如說,要查 Alice(ID = 1)選了哪些課,可以這樣查:

SELECT c.title
FROM courses c
JOIN enrollments e ON c.course_id = e.course_id
WHERE e.student_id = 1;

結果:

title
Mathematics
History

怎麼查一門課有哪些學生選?

假設你想知道誰選了 Mathematics(ID = 1):

SELECT s.name
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
WHERE e.course_id = 1;

結果:

name
Alice
Charlie

怎麼查所有學生跟他們選的課?

想要一次看到誰選了哪些課,可以這樣查:

SELECT s.name AS student, c.title AS course
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
JOIN courses c ON e.course_id = c.course_id;

結果:

student course
Alice Mathematics
Alice History
Bob Biology
Charlie Mathematics
Charlie History
Charlie Biology

enrollments 這個表讓我們的 schema 超彈性——你可以隨時加或刪學生跟課程的關聯,完全不用動到主表。用 JOIN 查詢也很方便,像是誰選了哪門課都能輕鬆查到。外鍵還會自動幫你檢查資料正確性——比如說,不會有人不小心選到根本不存在的課。

「多對多」關聯常見錯誤

沒有設唯一限制:如果沒設 PRIMARY KEY,一樣的關聯可能會被加好幾次。

資料完整性出錯:如果你插入一個不存在的 student_idcourse_id,就會出錯。

刪資料順序錯誤:如果你先把 courses 裡的課刪掉,enrollments 裡的資料就會變成「孤兒」。要避免這種情況,記得在外鍵定義裡加 ON DELETE CASCADE

1
問卷/小測驗
外部鍵,等級 19,課堂 4
未開放
外部鍵
外部鍵
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION