表中某欄位允許 NULL,NULL 可重複,但非 NULL 值必須唯一。例如:
CREATE TABLE test_tb (
TestId INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
Caption NVARCHAR(100) NULL
);
CREATE UNIQUE NONCLUSTERED INDEX un_test_tb ON test_tb(Caption);
測試插入兩個 NULL → 報錯 2601,SQL Server 視 NULL 為重複鍵值,不符合需求。
CREATE FUNCTION dbo.fn_CK_test_tb_Caption()
RETURNS BIT
AS
BEGIN
IF EXISTS (
SELECT 1 FROM test_tb a
WHERE a.Caption IS NOT NULL
AND EXISTS (
SELECT 1 FROM test_tb
WHERE Caption = a.Caption AND TestId <> a.TestId
)
) RETURN 0;
RETURN 1;
END;
ALTER TABLE test_tb
ADD CONSTRAINT CK_test_tb_Caption CHECK (dbo.fn_CK_test_tb_Caption() = 1);
測試:NULL 可多筆,'AAA'、'BBB' 正常,再插 'BBB' → 報錯。邏輯正確,但效能差、維護成本高。
CREATE UNIQUE NONCLUSTERED INDEX un_test_tb
ON test_tb(Caption)
WHERE Caption IS NOT NULL;
同樣測試通過,僅索引非 NULL 列,完美滿足需求。
| 方案 | 適用版本 | 優點 | 缺點 |
|---|---|---|---|
| 唯一索引 | 所有版本 | 簡單 | NULL 視為重複,不符合需求 |
| CHECK + 函數 | 所有版本 | 通用 | 效能差、程式碼冗長、並發下需額外處理 |
| 篩選索引 | SQL Server 2008+ | 原生支援、效能最佳、語法簡潔 | 舊版本無法使用 |
有無「兼容舊版本又優雅」的寫法?歡迎留言分享(如 INSTEAD OF INSERT/UPDATE 觸發器手工檢查、計算欄位 + 唯一索引等變通做法)。