10

我正在使用 SQL Server 2005。

我有一个必须包含唯一值或 NULL 值的字段。我认为我应该使用 aCHECK CONSTRAINT或 a来执行此操作TRIGGER for INSERT, UPDATE

在这里使用约束而不是触发器有优势吗(反之亦然)?这样的约束/触发器可能是什么样的?

还是我没有考虑过其他更合适的选择?

4

7 回答 7

6

我创建了一个带有索引的视图,该索引通过 where 子句忽略了空值……即,如果将空值插入表中,则视图不在乎,但如果插入非空值,则视图将强制执行约束。

create view dbo.UniqueAssetTag with schemabinding
as
select asset_tag
from dbo.equipment
where asset_tag is not null

GO

create unique clustered index ix_UniqueAssetTag
on UniqueAssetTag(asset_tag)

GO

所以现在我的设备表有一个asset_tag 列,它允许多个空值,但只允许唯一的非空值。

注意:如果使用 mssql 2000,您需要在对表执行任何插入、更新或删除之前“ SET ARITHABORT ON ”。很确定这在 mssql 2005 及更高版本上不是必需的。

于 2008-12-18T13:46:49.487 回答
4

这是使用约束的另一种方法。为了强制执行此约束,您需要一个计算字段值出现次数的函数。在您的约束中,只需确保此最大值为 1。

约束:

   field is null or dbo.fn_count_maximum_of_field(field) < 2

编辑我现在不记得了——也不能检查它——约束检查是在插入/更新之前还是之后完成的。我认为在插入/更新失败后回滚。如果事实证明我错了,上面的 2 应该是 1。

表函数返回一个 int 并使用以下选择来派生它

   declare @retVal int

   select @retVal = max(occurrences)
   from ( 
        select field, count(*) as occurrences
        from dbo.tbl
        where field = @field
        group by field
   ) tmp

如果您的列作为(非唯一)索引,这应该相当快。

于 2008-12-18T13:35:02.007 回答
3

您可以通过创建计算列并将唯一索引放在该列上来完成此操作。

ALTER TABLE MYTABLE 
ADD COL2 AS (CASE WHEN COL1 IS NULL THEN CAST(ID AS NVARCHAR(255)) ELSE COL1 END)

CREATE UNIQUE INDEX UQ_COL2 ON MYTABLE (COL2)   

这是假设 ID 是您的表的 PK 并且 COL1 是“唯一或空”列。

如果您的“唯一”列为空,则计算列 (COL2) 将使用 PK 的值。

在下面的示例中,ID 列和 COL1 之间仍然存在冲突的可能性:

ID     COL1    COL2
1     [NULL]    1
2        1      1

为了解决这个问题,我通常创建另一个计算列来存储 COL2 中的值是来自 ID 列还是来自 COL1 列:

 ALTER TABLE MYTABLE 
 ADD COL3 AS (CASE WHEN COL1 IS NULL THEN 1 ELSE 0 END)

索引应更改为:

CREATE UNIQUE INDEX UQ_COL2 ON MYTABLE (COL2, COL3)   

现在索引在计算列 COL2 和 COL3 上,所以没有问题:

ID     COL1    COL2   COL3
1     [NULL]    1       1
2        1      1       0
于 2009-11-17T20:54:20.297 回答
2

在 Oracle 中,唯一键将允许多个 NULL。

在 SQL Server 2005 中,一个好的方法是通过视图进行插入,并禁用直接插入到表中。

这是一些示例代码。

于 2008-12-18T13:18:27.827 回答
2

此表上是否有主键,可能是标识列?您可以创建一个唯一键,该键是您强制唯一性的字段与主键的组合。

这里有一个关于这类问题的讨论:http: //blog.sqlauthority.com/2008/09/07/sql-server-explanation-about-usage-of-unique-index-and-unique-constraint/

仅供参考 - SQL Server 2008 引入了过滤索引,这将允许您以不同的方式处理此问题。

于 2008-12-18T13:21:28.290 回答
0

通常触发器将允许您提供比检查约束更详细和解释性的消息,因此我使用它们来避免调试中的“哪一列是坏的”游戏。

于 2008-12-18T13:22:24.543 回答
0

约束远比触发器轻,即使唯一约束实际上是索引。

但是,在唯一约束/索引中只允许有一个 NULL。因此,您必须使用触发器来检测重复项。

MS已要求忽略 NULLS,但 SQL 2008 已过滤索引(如我键入时所述)

于 2008-12-18T13:24:58.860 回答