CodeGym /課程 /SQL SELF /使用 JOIN 時常見的錯誤

使用 JOIN 時常見的錯誤

SQL SELF
等級 12 , 課堂 4
開放

現在是時候聊聊人生了。人生總有那一面是逃不掉的:錯誤。抓 bug、修 bug、理解 bug——這就是搞資料一定會遇到的日常。來看看在 SQL 裡用 JOIN 時會踩到哪些地雷,還有怎麼閃過去。

錯誤 1:漏掉 JOIN 條件——產生笛卡兒積

最常見的錯誤就是——忘記寫 ON 條件。這樣會產生笛卡兒積,也就是第一張表的每一列都會跟第二張表的每一列配對。結果你會拿到一大堆沒意義的資料列,超級混亂。

舉個例子。假設我們有這兩張表:

學生 (students):

student_id name
1 Otto
2 Anna

課程 (courses):

course_id course_name
101 數學
102 歷史

現在我們寫個查詢,忘記 ON

SELECT *
FROM students
JOIN courses;

結果:

student_id name course_id course_name
1 Otto 101 數學
1 Otto 102 歷史
2 Anna 101 數學
2 Anna 102 歷史

這看起來完全不對吧?這種災難就叫做 笛卡兒積

怎麼修:ON 指定表格之間的關聯欄位。

SELECT *
FROM students
JOIN courses
ON students.student_id = courses.course_id;

然後又會遇到新一輪的錯誤...

防呆設計

這問題太常見了,所以 PostgreSQL 直接禁止你用 JOIN 但沒寫 ON 和條件。

如果你真的想每一列都配每一列,可以不用 JOIN,直接這樣寫:

SELECT *
FROM students, courses;

還有第 3 種情況——什麼時候 JOIN 不用 ON 也可以

  • NATURAL JOIN —— 會自動找名字一樣的欄位來連。
  • USING —— 你自己指定哪些欄位要連。
  • CROSS JOIN —— 永遠不用條件,就是笛卡兒積。

錯誤 2:JOIN 條件寫錯

有時候你有寫 JOIN 條件,但寫錯了。比如不是用 key 連,而是用一些根本沒關係的欄位。

假設我們想查學生和他們選的課程,但不小心用錯欄位來 JOIN:

SELECT *
FROM students
JOIN courses
ON students.student_id = courses.course_id;

這樣查出來的結果一定怪怪的,因為 student_idcourse_id 完全是兩回事。

怎麼修:確認你用對欄位來 JOIN。正確的 JOIN 可能長這樣(假設你有一張 enrollments 表來連學生和課程):

SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;

錯誤 3:結果資料列重複

當你查詢裡加了好幾個 JOIN,有時候會出現重複的資料列。這通常是因為 JOIN 的表裡有重複資料,或是 JOIN 條件寫錯。

比如 Otto 這個學生在 enrollments 表裡同一門課被記錄了兩次。

enrollments 裡的資料:

student_id course_id
1 101
1 101

現在用 JOIN 查會變這樣:

SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;

結果:

name course_name
Otto 數學
Otto 數學

怎麼修:第一,確保你的表裡沒有重複資料。第二,如果這是預期的行為,要去掉重複可以用 DISTINCT

SELECT DISTINCT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;

錯誤 4:用 INNER JOIN 會遺失資料列

INNER JOIN 只會回傳兩張表都有對應資料的列。如果其中一張表沒有對應值,那一列就會被丟掉。你可能會因為 JOIN 類型選錯而遺失資料。

比如有個學生還沒選任何課:

學生 (students):

student_id name
1 Otto
2 Anna
3 Dhany

選課紀錄 (enrollments):

student_id course_id
1 101
2 102

現在用 INNER JOIN 查:

SELECT students.name, courses.course_name
FROM students
JOIN enrollments ON students.student_id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.course_id;

結果:

name course_name
Otto 數學
Anna 歷史

那 Dhany 呢?如果你想把沒選課的學生也查出來,要用 LEFT JOIN

SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id;

錯誤 5:NULL 值處理不當

如果某張表有 NULL(空值),這些資料有可能被過濾掉(比如你加了 WHERE 條件)。

舉例:你用了 LEFT JOIN,但又加了 WHERE 來過濾。

SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id
WHERE courses.course_name = '數學';

這樣沒選課的學生還是查不出來,雖然你用了 LEFT JOIN

怎麼修:如果你想把沒課的學生也查出來,可以把 WHERE 換成 ON,或加一個條件:

SELECT students.name, courses.course_name
FROM students
LEFT JOIN enrollments ON students.student_id = enrollments.student_id
LEFT JOIN courses ON enrollments.course_id = courses.course_id
WHERE courses.course_name IS NULL OR courses.course_name = '數學';

錯誤 6:搞混 JOIN 類型

你會搞不清楚該用哪種 JOIN。比如用了 RIGHT JOIN,其實只要換一下表的順序就可以用 LEFT JOIN

怎麼避免混亂:

  • 能用 LEFT JOIN 就用,這樣比較直覺。
  • 換一下表的順序,就不用 RIGHT JOIN 了。
1
問卷/小測驗
多重 JOIN,等級 12,課堂 4
未開放
多重 JOIN
多重 JOIN
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION