本文 AI 產出,尚未審核

MySQL 條件查詢:IS NULLNOT NULL


簡介

在資料庫的日常操作中,NULL 扮演著「未知」或「缺失」的角色。與一般的數值、字串不同,NULL 不能直接以 =!= 來比較,必須使用專門的運算子 IS NULLIS NOT NULL 來判斷欄位是否為空。
如果對 NULL 的處理不夠熟悉,常會出現查詢結果不如預期、資料統計錯誤,甚至產生隱蔽的程式錯誤。因而掌握 IS NULL/IS NOT NULL 的正確用法,是每位 MySQL 使用者在條件查詢階段的必備功力。

本篇文章將從概念說明、實作範例、常見陷阱與最佳實踐,以及實務應用場景四個面向,完整闡述如何在 MySQL 中安全、有效地使用 IS NULLNOT NULL。本文適合 初學者到中級開發者,即使你僅會簡單的 SELECT,也能快速上手。


核心概念

1. 為什麼不能用 = NULL

在 SQL 標準裡,NULL 代表「未知」的值,任何與未知值的比較結果都是 UNKNOWN(三值邏輯:TRUE、FALSE、UNKNOWN)。因此:

SELECT * FROM users WHERE email = NULL;   -- 永遠不會回傳資料

上述語句永遠不會符合條件,因為 email = NULL 的結果是 UNKNOWN,而不是 TRUE。正確的寫法必須改用 IS NULL

SELECT * FROM users WHERE email IS NULL;

2. IS NULLIS NOT NULL 的語法

運算子 語意 範例
IS NULL 判斷欄位值是否為 NULL col IS NULL
IS NOT NULL 判斷欄位值是否 非 NULL col IS NOT NULL

注意IS NOT NULLNOT (col IS NULL) 等價,但前者可讀性更佳,且在優化器上表現更好。

3. NULL 與索引的互動

  • 普通 B‑Tree 索引IS NULL 可以使用索引(自 MySQL 5.7 起支援),但 IS NOT NULL 仍會走全表掃描,除非同時加入其他篩選條件。
  • 覆寫索引(Composite Index):若索引欄位中包含 NULL,MySQL 仍會把 NULL 作為索引鍵的一部份,允許透過 IS NULL 直接定位。

4. NULL 與聚合函式

聚合函式(COUNT()、SUM()、AVG())會自動忽略 NULL。若想計算 NULL 的筆數,必須配合 IS NULL

SELECT COUNT(*) AS total,
       COUNT(col) AS not_null,
       SUM(col IS NULL) AS null_cnt
FROM   table_name;

SUM(col IS NULL) 會把 TRUE(值 1)累加,得到 NULL 的筆數。


程式碼範例

以下示範 5 個常見情境,均以 employees 資料表為例(欄位:id、name、department_id、email、hire_date)。

範例 1:找出尚未填寫 Email 的員工

-- 只要 email 為 NULL 的列都會被挑出
SELECT id, name, hire_date
FROM   employees
WHERE  email IS NULL;

說明IS NULL 直接檢查欄位是否缺值,適合資料清理或提醒使用者補全資訊。


範例 2:找出已指定部門且部門編號非空的員工

SELECT id, name, department_id
FROM   employees
WHERE  department_id IS NOT NULL;

說明IS NOT NULL 可快速過濾掉「未分配部門」的資料;若再加上 department_id > 0,可避免意外的 0 或負值。


範例 3:結合 IS NULL 與其他條件(複合查詢)

-- 同時滿足以下兩個條件:
--   1. email 為 NULL
--   2. 入職日期在 2023 年以後
SELECT id, name, hire_date
FROM   employees
WHERE  email IS NULL
  AND  hire_date > '2023-01-01';

說明AND 結合多個條件時,MySQL 會先利用索引(若有)過濾 hire_date,再檢查 email IS NULL,提升效能。


範例 4:使用 IS NULLCASE 表達式中產生標記

SELECT id,
       name,
       CASE
         WHEN email IS NULL THEN '未填寫 Email'
         ELSE '已提供 Email'
       END AS email_status
FROM   employees;

說明:在報表或前端顯示時,CASE 讓 NULL 與非 NULL 產生不同的文字描述,提升可讀性。


範例 5:計算每個部門的 NULL Email 數量

SELECT department_id,
       COUNT(*) AS total_emp,
       SUM(email IS NULL) AS null_email_cnt
FROM   employees
GROUP BY department_id;

說明SUM(email IS NULL) 會把每筆 email IS NULL 為 TRUE 的列加 1,直接得到缺失的筆數,避免額外的子查詢。


常見陷阱與最佳實踐

陷阱 可能產生的問題 解決方法 / 最佳實踐
使用 =<> 判斷 NULL 查詢永遠回傳空集合 必須改用 IS NULL / IS NOT NULL
忘記考慮三值邏輯 WHERE col <> 5 會把 NULL 排除,可能誤以為「不等於 5」的結果包含 NULL 若要同時排除 NULL,寫成 WHERE col <> 5 AND col IS NOT NULL
WHERE 中混用 NULL 與函式 WHERE COALESCE(col, 0) = 0 會把原本的 NULL 變成 0,影響統計 直接使用 IS NULL,或明確說明 COALESCE 的意圖
索引失效 WHERE NOT (col IS NULL) 可能導致全表掃描 盡量寫成 WHERE col IS NOT NULL,必要時加上其他可使用索引的條件
聚合時忽略 NULL AVG(salary) 不會把 NULL 當作 0,可能低估平均值 若需要把 NULL 視為 0,使用 AVG(COALESCE(salary,0));若想知道有多少 NULL,另寫 SUM(salary IS NULL)

最佳實踐小結

  1. 永遠使用 IS NULL / IS NOT NULL 取代 =!=
  2. 結合索引:在可行的情況下,把 IS NULL 放在索引欄位上,或同時加上其他索引條件。
  3. 明確三值邏輯:在需要排除 NULL 時,務必加上 col IS NOT NULL
  4. 利用 CASE / COALESCE:在輸出層面把 NULL 轉換成易讀文字或預設值。
  5. 測試與驗證:使用 EXPLAIN 檢視查詢計畫,確保不會因為 NULL 判斷而產生不必要的全表掃描。

實際應用場景

  1. 使用者資料完整度檢查

    • 定期跑 SELECT * FROM users WHERE phone IS NULL OR address IS NULL;,找出缺失欄位,發送提醒郵件給使用者。
  2. 報表與儀表板

    • 在銷售報表中,SUM(order_amount IS NULL) 可快速顯示「尚未填寫金額」的訂單筆數,協助業務團隊追蹤資料落差。
  3. 資料遷移與清理

    • 在將舊系統資料搬入新資料庫前,先用 SELECT * FROM old_table WHERE critical_col IS NULL; 找出必須補齊的關鍵欄位,避免因為 NULL 而觸發唯一鍵衝突。
  4. 條件授權

    • 某些功能只對已完成驗證的帳號開放:WHERE email_verified_at IS NOT NULL
  5. 多表 JOIN 的排除

    • 在左連接(LEFT JOIN)後,若需要找出「在左表有,但右表沒有對應資料」的列,可使用 WHERE right_table.id IS NULL 來判斷。

總結

  • NULL 不是資料,而是「未知」或「缺失」的狀態,必須使用 IS NULL / IS NOT NULL 來正確判斷。
  • 了解 三值邏輯、索引行為以及聚合函式對 NULL 的處理方式,可避免常見的查詢錯誤與效能問題。
  • 透過 案例最佳實踐實務場景,你可以在日常的 MySQL 開發與維運中,快速定位缺失資料、提升報表品質、降低系統錯誤率。

掌握了 IS NULLNOT NULL 的正確使用,你的資料庫查詢將變得更可靠可讀高效。祝你在 MySQL 的旅程中,持續寫出乾淨、正確的 SQL!