欄位允許 NULL,但非 NULL 時必須唯一。UNIQUE 約束會限制只能有一個 NULL。
ALTER TABLE 表 ADD 非NULL唯一鍵 AS CASE WHEN 欄位 IS NULL THEN NULL ELSE 欄位 END
CREATE UNIQUE INDEX UX_表_非NULL唯一 ON 表(非NULL唯一鍵) WHERE 非NULL唯一鍵 IS NOT NULL
或直接建立過濾索引:
CREATE UNIQUE INDEX UX_表_欄位_非NULL ON 表(欄位) WHERE 欄位 IS NOT NULL
CREATE FUNCTION fn_CheckUnique(@val INT) RETURNS BIT AS BEGIN
DECLARE @cnt INT
SELECT @cnt = COUNT(*) FROM 表 WHERE 欄位 = @val
RETURN CASE WHEN @cnt > 1 THEN 0 ELSE 1 END
END
GO
ALTER TABLE 表 ADD CONSTRAINT CK_非NULL唯一
CHECK (欄位 IS NULL OR dbo.fn_CheckUnique(欄位) = 1)
CREATE TRIGGER tr_CheckUnique ON 表 FOR INSERT, UPDATE AS
IF EXISTS (
SELECT 1 FROM inserted i JOIN 表 t ON i.欄位 = t.欄位
WHERE i.欄位 IS NOT NULL
GROUP BY i.欄位 HAVING COUNT(*) > 1
)
ROLLBACK TRAN
SQL Server 2008+ 優先使用過濾唯一索引,效能最好、無額外函數呼叫、維護最簡單。