在 SQL Server 開發與維護過程中,NULL 值的處理往往是導致查詢結果偏差、資料完整性受損的隱形殺手。本文深入剖析三大核心場景——聚合計數、空表值引用、可為 NULL 的外鍵驗證,並提供最佳實踐與代碼範例,助你避開陷阱、寫出健壯的 T-SQL 代碼。
大多數聚合函數(SUM、AVG、MIN、MAX)會自動忽略 NULL 值,但 COUNT 函數的行為取決於參數形式:
SET NOCOUNT ON;
GO
CREATE TABLE xCount (
pkey1 INT IDENTITY NOT NULL CONSTRAINT pk_xCount PRIMARY KEY,
Col1 INT NULL
);
GO
INSERT xCount (Col1) VALUES (10), (15), (20), (NULL);
GO
SELECT
AVG(Col1) AS Avg_Ignore_Null,
AVG(ISNULL(Col1, 0)) AS Avg_Treat_Null_As_Zero,
COUNT(Col1) AS Count_Col1_Ignore_Null,
COUNT(ISNULL(Col1, 0)) AS Count_Col1_Include_Null,
COUNT(*) AS Count_All_Rows
FROM xCount;
GO
DROP TABLE xCount;
GO
| Avg_Ignore_Null | Avg_Treat_Null_As_Zero | Count_Col1_Ignore_Null | Count_Col1_Include_Null | Count_All_Rows |
|---|---|---|---|---|
| 15 | 11 | 3 | 4 | 4 |
關鍵技巧:若需在聚合計算中納入 NULL 值,請使用 ISNULL(列, 替代值) 或 COALESCE 將其轉換為具體數值再參與運算。
即使父表主鍵列無 NULL 值,子表外鍵列若允許 NULL,仍可插入 NULL 值。這在業務邏輯上代表「關聯尚未建立」(如暫未分配的聯繫地址),屬合法情況,但需謹慎設計。
-- 建立父表
CREATE TABLE Parent (
pkey1 INT IDENTITY NOT NULL CONSTRAINT pkParent PRIMARY KEY,
col1 INT NULL
);
INSERT Parent (col1) VALUES (284), (326);
-- 建立子表,外鍵允許 NULL
CREATE TABLE Child (
pkey1 INT IDENTITY CONSTRAINT pkChild PRIMARY KEY,
Parentpkey1 INT NULL CONSTRAINT fkChildParent FOREIGN KEY REFERENCES Parent(pkey1),
col1 INT NULL
);
INSERT Child (Parentpkey1, col1) VALUES (NULL, 2); -- 合法插入
-- 查詢驗證
SELECT * FROM Child;
SELECT * FROM Parent;
DROP TABLE Child, Parent;
提示:若業務要求「必須關聯」,諈在子表外鍵列加上 NOT NULL 約束;若允許暫時無關聯,則保留 NULL 並在應用層處理業務邏輯。
當複合主鍵(多列)被作為可為 NULL 的外鍵繼承時,可能出現「一列有值、另一列為 NULL」的異常資料,導致引用完整性失效。
針對所有構成外鍵的列,建立「要么全非 NULL,要么全 NULL」的檢查約束:
ALTER TABLE Child
ADD CONSTRAINT chk_Composite_FK_Valid
CHECK (
(ParentKey1 IS NULL AND ParentKey2 IS NULL) -- 全 NULL 允許
OR (ParentKey1 IS NOT NULL AND ParentKey2 IS NOT NULL) -- 全非 NULL 允許
);
此約束確保不會出現「部分 NULL」的無效組合,從根源上保障資料品質。
掌握這三大核心點,即可在 SQL Server 中自信駕馭 NULL 值,構建高可靠性的資料庫應用。