如何为2个可空列添加唯一约束?

时间:2013-02-01 15:55:12

标签: sql-server sql-server-2008

谁知道如何在两列中都允许使用NULLS创建2列的唯一约束?我的意思是忽略col1 = NULL和col2 = NULL的唯一性,但是如果只有其中一个是NULL,那么让约束工作吗?我找到了如何为单列(How do I create a unique constraint that also allows nulls?)执行此操作,但无法将其用于2列。这是我的脚本,它适用于现有记录(多个NULL,允许NULL),但不允许添加任何新的NULL,NULL记录:

CREATE UNIQUE NONCLUSTERED INDEX MyIndex ON dbo.MyTable(col1, col2)     
WHERE col1 IS NOT NULL AND col2 IS NOT NULL

更新:嗯,它允许你添加新的(NULL,NULL)值,所以我错了,但它也允许你添加像(1,NULL),(1,NULL)这样我不喜欢的东西,所以唯一性适用于这种情况,只允许多个(NULL,NULL)。怎么做?

2 个答案:

答案 0 :(得分:2)

其他一些肯定不起作用。您的代码/脚本按预期工作:

CREATE TABLE #MyTable
(
    Col1 INT NULL,
    Col2 INT NULL
)

CREATE UNIQUE NONCLUSTERED INDEX MyIndex ON #MyTable(col1, col2)     
WHERE col1 IS NOT NULL AND col2 IS NOT NULL

INSERT INTO #MyTable(Col1, Col2)
VALUES(NULL, NULL) --Works

INSERT INTO #MyTable(Col1, Col2)
VALUES(NULL, NULL) --Works

SELECT * FROM #MyTable

INSERT INTO #MyTable(Col1, Col2)
VALUES(1, 1) --Works

INSERT INTO #MyTable(Col1, Col2)
VALUES(1, 1) --Fails

SELECT * FROM #MyTable

DROP TABLE #MyTable

答案 1 :(得分:1)

如果希望值是唯一的,除非两者都为null,这意味着只要至少有一个值不为null,就希望它们是唯一的。您对索引的过滤器有AND,但您需要OR

CREATE UNIQUE NONCLUSTERED INDEX MyIndex ON dbo.MyTable(col1, col2)     
WHERE col1 IS NOT NULL OR col2 IS NOT NULL -- (note: doesn't work)

然而......你不能这样做。 SQL Server将only let you create a where clause with AND conditions。你也can't use a persisted computed column来做。

相反,您可以做的是在原始表上创建索引视图,然后将唯一索引放在 上。它有点重量级,但它应该有效。

所以...借用@ Meff的剧本,你会看到类似的东西:

CREATE TABLE dbo.MyTable
(
    Col1 INT NULL,
    Col2 INT NULL
)
GO
CREATE VIEW dbo.MyTableUniqueView WITH SCHEMABINDING AS
SELECT Col1, Col2 FROM dbo.MyTable
WHERE Col1 IS NOT NULL OR Col2 IS NOT NULL 
GO
CREATE UNIQUE CLUSTERED INDEX MyTableUniqueIndex
ON dbo.MyTableUniqueView(Col1, Col2)
GO
INSERT INTO MyTable(Col1, Col2)
VALUES(NULL, NULL) --Works

INSERT INTO MyTable(Col1, Col2)
VALUES(NULL, NULL) --Works

SELECT * FROM MyTable

INSERT INTO MyTable(Col1, Col2)
VALUES(1, 1) --Works

INSERT INTO MyTable(Col1, Col2)
VALUES(1, 1) --Fails

INSERT INTO MyTable(Col1, Col2)
VALUES(1, null) --Works

INSERT INTO MyTable(Col1, Col2)
VALUES(1, null) --Fails

SELECT * FROM MyTable
GO
DROP VIEW MyTableUniqueView
DROP TABLE MyTable