在資料庫世界裡,NULL 不只是「沒有值」這麼簡單——它代表「未知」或「不適用」,是關聯式資料庫理論的核心概念之一。Oracle 對 NULL 的處理有其獨特規則,若不深入理解,極易在查詢、統計、索引等環節踩坑。本文以經典 EMP 員工表為例,系統梳理 NULL 的生成機制、核心特性、測試方法、運算邏輯、函數行為、排序與索引特性,助你建立完整的 NULL 知識體系。
NOT NULL 或 PRIMARY KEY 約束的欄位,插入資料時若未指定值,自動成為 NULL。INSERT INTO emp(empno, ename) VALUES (1, 'JIA');未列出的欄位全部變為 NULL。INSERT ... VALUES (..., NULL, ...);字元型也可用 ''(兩個單引號)表示。UPDATE emp SET comm = NULL WHERE empno = 7369。| 特性 | 說明 | 實務影響 |
|---|---|---|
| 等價於「無值」 | 非 0、非空字串、非空格 | 不可用 =、!= 比較 |
| 三值邏輯 | 比較結果為 NULL(非 TRUE/FALSE) | WHERE 視為 FALSE,不報錯也不回傳列 |
| 排序最大 | ORDER BY col ASC 時 NULL 排最後 | 需用 NULLS FIRST/LAST 明確控制 |
| 不可被索引 | B-tree 索引不儲存全 NULL 的鍵值 | WHERE col IS NULL 走全表掃描;但可建唯一索引(多筆 NULL 不違反唯一性) |
| 運算傳染 | 任何算術/字串運算含 NULL,結果皆為 NULL | sal + comm 若 comm 為 NULL,總薪資變 NULL |
錯誤寫法:
WHERE mgr = '' -- 字元型空字串,非 NULL
WHERE mgr = NULL -- 永遠回傳 UNKNOWN,等同 FALSE
正確寫法:
WHERE mgr IS NULL -- 找出無主管的員工(如 KING)
WHERE mgr IS NOT NULL -- 找出有主管的員工
DECODE 例外:DECODE(col, NULL, 'A', 'B') 視兩個 NULL 為相等,這是 Oracle 歷史相容設計。
| 運算 | NULL AND TRUE | NULL AND FALSE | NULL AND NULL | NULL OR TRUE | NULL OR FALSE | NULL OR NULL | NOT NULL |
|---|---|---|---|---|---|---|---|
| 結果 | NULL | FALSE | NULL | TRUE | NULL | NULL | NULL |
關鍵啟示:NULL AND FALSE = FALSE、NULL OR TRUE = TRUE 是僅有的「短路」情況;其餘含 NULL 運算皆產生 NULL,進而導致 WHERE 過濾掉該列。
| 運算子類別 | 表達式範例 | 結果 | 備註 |
|---|---|---|---|
| IS [NOT] NULL | a IS NULL | TRUE | 唯一可靠測試 |
| a IS NOT NULL | FALSE | ||
| c IS NULL | FALSE | ||
| c IS NOT NULL | TRUE | ||
| = != > < >= <= | a = NULL | NULL | 含 NULL 必為 NULL |
| a > NULL | NULL | ||
| c = NULL | NULL | ||
| c > NULL | NULL | ||
| IN (=ANY) | a IN (10, NULL) | NULL | 等價於 OR 串聯 |
| c IN (10, NULL) | TRUE | ||
| c IN (20, NULL) | NULL | ||
| NOT IN (!=ALL) | a NOT IN (20, NULL) | NULL | 等價於 AND 串聯,極易踩坑 |
| c NOT IN (20, NULL) | FALSE | ||
| c NOT IN (10, NULL) | NULL | ||
| ANY / SOME | a > ANY(5, NULL) | NULL | 同 IN 邏輯 |
| c > ANY(5, NULL) | TRUE | ||
| c > ANY(15, NULL) | NULL | ||
| ALL | a > ALL(5, NULL) | NULL | 同 NOT IN 邏輯 |
| c > ALL(5, NULL) | NULL | ||
| c > ALL(15, NULL) | FALSE | ||
| (NOT) BETWEEN | a BETWEEN 5 AND NULL | NULL | 展開為 >= AND <= |
| c BETWEEN 5 AND NULL | NULL | ||
| c BETWEEN 15 AND NULL | FALSE | ||
| a NOT BETWEEN 5 AND NULL | NULL | ||
| c NOT BETWEEN 5 AND NULL | NULL | ||
| c NOT BETWEEN 15 AND NULL | TRUE |
NULL + 10 = NULL、sal + comm 任一為 NULL 則總和為 NULL。'' 視同 NULL,故 ename || mgr 若 mgr 為 NULL,結果等同 ename(非標準 SQL 行為,未來版本可能改變)。除 NVL、NVL2、COALESCE、TRANSLATE 外,參數為 NULL 時回傳 NULL。
例:ABS(comm)、UPPER(ename) 皆同理。
預設忽略 NULL:COUNT(comm)、SUM(comm)、AVG(comm) 只統計非 NULL 列。
若需把 NULL 視為 0 參與計算,必須用 NVL(comm,0) 包裹。
| 寫法 | 邏輯 | NULL 處理 |
|---|---|---|
SUM(sal + comm) | 先逐列相加再彙總 | 任一為 NULL → 該列不計入 |
SUM(sal) + SUM(comm) | 先各自彙總再相加 | 各自忽略 NULL;若任一彙總為 NULL(如全 NULL),結果為 NULL |
SUM(NVL(sal,0) + NVL(comm,0)) | 先以 0 取代 NULL 再加總 | 所有列皆參與,最直觀 |
SELECT ename, comm FROM emp WHERE deptno = 30 ORDER BY comm;
-- 結果:0, 300, 500, 1400, NULL, NULL(NULL 排最後)
若需 NULL 排最前:ORDER BY comm NULLS FIRST。
因 B-tree 不存全 NULL 鍵值,同一欄位允許無限筆 NULL 且不違反 UNIQUE 約束:
CREATE UNIQUE INDEX emp_comm_uq ON emp(comm); -- 成功,即使 comm 有多筆 NULL
但查詢 WHERE comm IS NULL 無法使用此索引,仍需全表掃描。
IS NULL / IS NOT NULL。NOT IN 子查詢若可能回傳 NULL,改用 NOT EXISTS 或 LEFT JOIN ... IS NULL。NVL(col, 0) 或 COALESCE,避免統計偏差。CONCAT 或 || 搭配 NVL,明確控制 NULL 顯示。CREATE INDEX idx_emp_comm_null ON emp(CASE WHEN comm IS NULL THEN 1 END)。NOT NULL 約束,減少應用層防禦性程式碼。掌握 NULL 的三值邏輯與傳染特性,是寫出正確、高效 Oracle SQL 的基石。願這份筆記能成為你開發時的隨身速查表。