CodeGym /課程 /SQL SELF /多個 JOIN 在同一個查詢裡

多個 JOIN 在同一個查詢裡

SQL SELF
等級 12 , 課堂 1
開放

想像一下,你資料庫裡的每一張 table 就像拼圖的一塊。學生 table 知道 誰在唸書,課程 table 負責 教什麼,而選課紀錄 table 則記著 誰選了什麼課。但這些拼圖單獨看都沒啥意思。想看全貌?就得把它們拼起來——這時候 多重 JOIN 就派上用場啦!

現實中,資料常常會拆成多個關聯 table,這樣才有結構又不會重複。像我們這個大學資料庫就有這幾張 table:

  • students — 學生資料。
  • enrollments — 學生選課紀錄。
  • courses — 課程資訊。

如果你想查出所有學生、他們的課程還有老師,就得用 JOIN 把這三張 table 串起來。

JOIN 的執行順序

當你用多個 JOIN 時,PostgreSQL 會從左到右處理。也就是說,先把前兩張 table 合起來,再把結果跟第三張 table 合,依此類推。

舉個例子:

SELECT *
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id;
  1. 先把 studentsenrollmentsstudents.id = enrollments.student_id 合起來。
  2. 然後用第一步的結果,跟 coursesenrollments.course_id = courses.id 再合一次。

這個順序很重要,尤其是 table 很大的時候。如果 JOIN 寫得不對,效能會掉超多。

範例:學生、課程和老師清單

假設我們有這些資料表:

students table:

id name
1 Otto Song
2 Maria Chi
3 Alex Lin

courses table:

id name teacher
101 Mathematics Ellen Moore
102 Physics James Okoro
103 Computer Science Nina Delgado

enrollments table:

student_id course_id
1 101
1 103
2 102
3 101

查詢:

SELECT
    students.name AS student_name,
    courses.name AS course_name,
    courses.teacher AS teacher_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id;

結果:

student_name course_name teacher_name
Otto Song Mathematics Ellen Moore
Otto Song Computer Science Nina Delgado
Maria Chi Physics James Okoro
Alex Lin Mathematics Ellen Moore

多重 JOIN 查詢裡的篩選

你可以在 JOIN 查詢裡加條件,這樣可以減少回傳的資料量,也讓查詢更快。比如只想看有修 "Mathematics" 的學生:

SELECT
    students.name AS student_name,
    courses.name AS course_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id
WHERE courses.name = 'Mathematics';

結果:

student_name course_name
Otto Song Mathematics
Alex Lin Mathematics

多重 JOIN 查詢的優化

面對大 table,查詢優化超重要。這裡有幾個小撇步:

  1. 用 index

index 讓 PostgreSQL 查資料快很多,特別是用在 key 欄位的時候。記得在 enrollmentsstudent_idcourse_id 上都要有 index。

建立 index 的範例:

CREATE INDEX idx_enrollments_student_id ON enrollments(student_id);
CREATE INDEX idx_enrollments_course_id ON enrollments(course_id);

index 之後會再講更多,不過這裡先提一下,因為 JOIN 常常會用到。

  1. 一開始就先篩掉不要的資料

WHERE 先把不需要的資料過濾掉,這樣 JOIN 前資料量就少很多。像這樣:

SELECT
    students.name AS student_name,
    courses.name AS course_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id
WHERE 
    courses.teacher = '伊凡 彼得羅夫';
  1. 減少要 JOIN 的資料量

不要直接把兩張 table 全部資料都 JOIN,先用子查詢過濾一下:

SELECT
    students.name AS student_name,
    courses.name AS course_name
FROM 
    (SELECT * FROM students WHERE id IN (1, 2)) sub_students
INNER JOIN enrollments ON sub_students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id;

子查詢(subquery)之後馬上就會學到啦 :P

進階範例:學生、課程和學院

假設我們又多了一張 faculties table:

faculties table:

id name
10 Engineering
20 Natural Sciences

courses table 更新:

id name teacher faculty_id
101 Mathematics Ellen Moore 10
102 Physics James Okoro 20
103 Computer Science Nina Delgado 10

要查學生、課程和學院,就再多加一個 JOIN

SELECT
    students.name AS student_name,
    courses.name AS course_name,
    faculties.name AS faculty_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id
    INNER JOIN faculties ON courses.faculty_id = faculties.id;

結果:

student_name course_name faculty_name
Otto Song Mathematics Engineering
Otto Song Computer Science Engineering
Maria Chi Physics Natural Sciences
Alex Lin Mathematics Engineering

多個 JOIN 的 SQL 查詢雖然有點複雜,但你可以用它們做出很強大的報表,挖出很多有用的資訊。只要優化和結構寫得好,它們就是你玩大資料庫的神兵利器!

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION