NULL 本質:不是空、不是零、是「未知」
- 定義: 值不存在、值未知、或列對該行不適用。
- 合法性: 同樣是合法值,可存儲於任何允許 NULL 的列。
三大核心差異
| 操作 | 普通值 | NULL |
| = 比較 | True/False | Unknown(非 True/False) |
| <> 比較 | True/False | Unknown |
| 邏輯運算 | True/False | 三值邏輯 |
| 聚合函數 | 參與計算 | 自動忽略(COUNT(*) 除外) |
| 排序 | 按值序 | 視為最小值(ASC 首位) |
實戰陷阱與正確寫法
1. WHERE 子句過濾
-- 錯誤:WHERE col = NULL 永遠返回空
-- 正確:
WHERE col IS NULL
WHERE col IS NOT NULL
2. NOT IN 子查詢陷阱
-- 若子查詢結果含 NULL,整個 NOT IN 永遠為 Unknown(無行返回)
SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2); -- 危險!
-- 安全寫法:
SELECT * FROM t1 WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE t2.id = t1.id);
-- 或
SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2 WHERE id IS NOT NULL);
3. 連接字符串
-- 'abc' + NULL = NULL
-- 解決:
SELECT ISNULL(col, '') + 'suffix';
SELECT CONCAT(col, 'suffix'); -- SQL 2012+ 自動忽略 NULL
4. 聚合與統計
COUNT(col) 不計 NULL,COUNT(*) 計行數。
AVG/SUM 忽略 NULL,但全 NULL 組返回 NULL。
5. 唯一索引與 NULL
- SQL Server 允許單個 NULL於唯一索引列(視為唯一值)。
- 多行 NULL 會違反唯一約束 → 需用過濾索引:
CREATE UNIQUE INDEX ... WHERE col IS NOT NULL。
ANSI_NULLS 設置影響
SET ANSI_NULLS ON(默認/推薦):= NULL 為 Unknown,必須用 IS NULL。
OFF(已棄用):允許 = NULL 返回 True,嚴重破壞可移植性與邏輯一致性。
最佳實踐清單
- 業務上「不適用」優於「未知」——優先設計
NOT NULL + 默認值。
- 所有比較、連接、聚合邏輯顯式處理 NULL。
- 使用
ISNULL/COALESCE/NULLIF 標準化輸出。
- 檢查約束:
CHECK (col IS NOT NULL OR other_col IS NULL) 表達業務互斥。
- ETL 階段做數據剖析,量化 NULL 佔比與分布。