想像一下你要合併兩個資料表:students(學生)和 enrollments(課程登記)。如果 enrollments 裡沒有某個學生的資料,但你用了 LEFT JOIN,那 students 的資料還是會出現,只是 enrollments 的資料會消失。這時候就會看到 NULL 出現啦。
大概長這樣:
資料表 students:
| id | name |
|---|---|
| 1 | Eva |
| 2 | Peter |
| 3 | Anna |
資料表 enrollments:
| student_id | course_name |
|---|---|
| 1 | 數學 |
| 1 | 資訊學 |
| 2 | 物理 |
用 LEFT JOIN 的查詢:
SELECT students.id, students.name, enrollments.course_name
FROM students
LEFT JOIN enrollments ON students.id = enrollments.student_id;
結果:
| id | name | course_name |
|---|---|---|
| 1 | Eva | 數學 |
| 1 | Eva | 資訊學 |
| 2 | Peter | 物理 |
| 3 | Anna | NULL |
哈囉,NULL!你看,Anna 沒有登記任何課程,課程資訊就不見了,直接顯示 NULL。
NULL 會怎麼影響查詢?
NULL 不是「零」也不是「空字串」,它是沒有值。這種行為有時候很有趣(有時候很煩):
跟 NULL 比較:
如果你寫 WHERE course_name = NULL,查詢是找不到 NULL 的。為什麼?因為 NULL 不能直接比較。
要檢查是不是 NULL,要用特別的語法:
WHERE course_name IS NULL
數學運算:
任何跟 NULL 的運算都會變成 NULL。像這樣:
SELECT 5 + NULL; -- 結果:NULL
聚合函數:
大部分聚合函數像 SUM()、AVG() 都會忽略 NULL,但 COUNT(*) 會把它們算進去(因為它算的是「有幾列」)。
怎麼處理 NULL?
- 用
COALESCE()把NULL換成比較好懂的值
COALESCE() 可以把 NULL 換成你想要的東西。比如課程沒資料時,顯示 "沒有課程":
SELECT
students.id,
students.name,
COALESCE(enrollments.course_name, '沒有課程') AS course_name
FROM
students LEFT JOIN enrollments
ON students.id = enrollments.student_id;
結果:
| id | name | course_name |
|---|---|---|
| 1 | Eva | 數學 |
| 1 | Eva | 資訊學 |
| 2 | Peter | 物理 |
| 3 | Anna | 沒有課程 |
這樣看起來是不是順眼多了?
- 過濾
NULL值
如果你不想看到 NULL 的列,可以用 WHERE ... IS NOT NULL。像這樣:
SELECT
students.id,
students.name,
enrollments.course_name
FROM
students LEFT JOIN enrollments
ON students.id = enrollments.student_id
WHERE
enrollments.course_name IS NOT NULL;
結果:
| id | name | course_name |
|---|---|---|
| 1 | Eva | 數學 |
| 1 | Eva | 資訊學 |
| 2 | Peter | 物理 |
Anna 就不見了,因為她沒有任何課程登記。
- 計算時考慮
NULL:COUNT的例子
前面說過,有些函數會忽略 NULL,有些不會。舉例:
要算所有列(包含 course_name 是 NULL 的):
SELECT COUNT(*) FROM students; -- 算所有列(不管 `course_name` 是不是 NULL)
只算 course_name 不是 NULL 的:
SELECT COUNT(course_name) FROM enrollments;
- 用
CASE條件判斷
如果你不愛 COALESCE() 或想要更彈性的處理,可以用 CASE。像這樣:
SELECT
students.id,
students.name,
CASE
WHEN enrollments.course_name IS NULL THEN '沒有課程'
ELSE enrollments.course_name
END AS course_name
FROM
students LEFT JOIN enrollments
ON students.id = enrollments.student_id;
結果會跟用 COALESCE() 一樣,但 CASE 可以寫更複雜的規則。
- 如果你確定不會有
NULL,就用INNER JOIN
最激進的方式就是根本不讓 NULL 出現,直接用 INNER JOIN。這種 join 只會回傳兩個表都有對應資料的列:
SELECT
students.id,
students.name,
enrollments.course_name
FROM
students INNER JOIN enrollments
ON students.id = enrollments.student_id;
沒意外——只有有登記課程的學生才會出現。
結果:
| id | name | course_name |
|---|---|---|
| 1 | Eva | 數學 |
| 1 | Eva | 資訊學 |
| 2 | Peter | 物理 |
如果你需要顯示所有資料(包含 NULL),那 INNER JOIN 就不適合,但有時候這樣就夠用了。
GO TO FULL VERSION