CodeGym /課程 /SQL SELF /處理 NULL 值在資料合併時

處理 NULL 值在資料合併時

SQL SELF
等級 12 , 課堂 0
開放

想像一下你要合併兩個資料表: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

  1. 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 沒有課程

這樣看起來是不是順眼多了?

  1. 過濾 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 就不見了,因為她沒有任何課程登記。

  1. 計算時考慮 NULLCOUNT 的例子

前面說過,有些函數會忽略 NULL,有些不會。舉例:

要算所有列(包含 course_nameNULL 的):

SELECT COUNT(*) FROM students; -- 算所有列(不管 `course_name` 是不是 NULL)

只算 course_name 不是 NULL 的:

SELECT COUNT(course_name) FROM enrollments;
  1. 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 可以寫更複雜的規則。

  1. 如果你確定不會有 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 就不適合,但有時候這樣就夠用了。

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