這堂課我們會更深入認識這個神祕的朋友 NULL。當然啦,你自己踩雷的時候還在後面,不過……先知道就先有防備。來看看幾個跟 NULL 有關的典型錯誤。
錯誤 1:用一般的 = 運算子檢查 NULL
大概所有 SQL 新手最常犯的錯誤,就是想用 = 來檢查某個值是不是 NULL。
發生什麼事?
SELECT *
FROM students
WHERE age = NULL;
你可能天真地以為這樣會查出所有年齡未知的學生,結果會失望:這個查詢啥都不會回傳。為什麼?因為 NULL 不是一個值,所以一般的比較運算子對它沒用。就像 SQL 魔法書裡說的:「NULL 不能直接跟任何東西比較」。
正確做法?
要檢查是不是 NULL,請用 IS NULL:
SELECT *
FROM students
WHERE age IS NULL;
這樣你就能查到所有沒填年齡的學生啦。
錯誤 2:聚合函數會忽略 NULL(除了 COUNT(*))
當你用聚合函數查詢時,NULL 會自動被排除在計算之外。這有時會讓你得到意外的結果。
發生什麼事?
SELECT AVG(salary) AS avg_salary
FROM employees;
如果 salary 欄位裡有 NULL,這些資料列會被直接忽略,平均薪資就不會算進去這些紀錄。這可能會讓你對平均薪資產生錯誤的印象。
怎麼避免?
在做聚合前,記得把 NULL 換成預設值。比如可以用 COALESCE():
SELECT AVG(COALESCE(salary, 0)) AS avg_salary
FROM employees;
這樣 NULL 會先被換成 0 再計算。
錯誤 3:把 NULL 拿來互相比較
在資料庫裡 NULL 連自己都不等於自己,這點很容易讓人傻眼。
發生什麼事?
SELECT *
FROM students
WHERE NULL = NULL;
這個查詢一樣會回傳空結果。為什麼?因為 SQL 認為一個不存在的值不可能「等於」另一個不存在的值。沒錯,SQL 很哲學 XD。
正確做法?
如果你想檢查兩個 NULL 是否「都為空」,要用像 IS NULL 這種語法。例如:
SELECT *
FROM students
WHERE first_name IS NULL AND last_name IS NULL;
錯誤 4:拿 NULL 來做除法
用 NULL 當除數不只是錯誤,根本是數學犯罪,SQL 會直接給你一個沒意義的結果——NULL。
發生什麼事?
SELECT 10 / NULL AS result;
結果?NULL。SQL 連想都不想幫你算。
怎麼避免?
想讓查詢更安全,可以用 COALESCE() 或 NULLIF():
SELECT 10 / COALESCE(divisor, 1) AS result
FROM calculations;
這樣如果 divisor 是 NULL,就會用 1 來除,不會出錯。
錯誤 5:邏輯運算子遇到 NULL 會壞掉
NULL 一碰到邏輯運算,整個邏輯就崩壞了。像 TRUE AND NULL 會回傳 NULL,不是 TRUE 也不是 FALSE。
發生什麼事?
SELECT *
FROM students
WHERE age > 18 OR age = NULL;
這時就算 age > 18 對某些資料列成立,有 age 是 NULL 的資料還是可能被排除。為什麼?因為 age = NULL 這段會回傳 NULL,不是 TRUE。
正確做法?
邏輯條件裡一定要明確處理 NULL:
SELECT *
FROM students
WHERE age > 18 OR age IS NULL;
錯誤 6:排序 NULL 時的隱性行為(最「重」的錯誤)
如果查詢裡用了 ORDER BY,NULL 的排序方式可能會讓你嚇一跳。預設情況下,PostgreSQL 會把 NULL 排在升冪的最後、降冪的最前面。
發生什麼事?
SELECT product_name, price
FROM products
ORDER BY price;
如果 price 是 NULL,這些資料會排在清單最後面。
怎麼避免意外?
你可以用 NULLS FIRST 或 NULLS LAST 來明確指定 NULL 的排序:
SELECT product_name, price
FROM products
ORDER BY price NULLS FIRST;
錯誤 7:外鍵和 NULL 的奇怪互動
外鍵欄位裡的 NULL 有時會讓你遇到很奇怪的行為。
發生什麼事?
如果你在資料表加了外鍵,然後插入資料時把外鍵欄位留空,PostgreSQL 會完全沒反應。因為 NULL 不會去檢查跟關聯表的對應。
正確做法?
如果你不想讓 NULL 出現在這種欄位,請加上 NOT NULL 限制。或者你要知道,NULL 這些資料就像「孤兒」,不屬於任何關聯表。
更多關於關聯表和外鍵的內容,下堂課再聊 :P
GO TO FULL VERSION