201

我有一张桌子,不知何故,同一个人Person两次上了我的桌子。现在,主键只是一个自动编号,但还有另外两个字段,我想强制它们是唯一的。

例如,这些字段是:

ID  
Name  
Active  
PersonNumber  

我只想要 1 条具有唯一 PersonNumber 且 Active = 1 的记录。
(因此这两个字段的组合需要是唯一的)

SQL Server 中现有表的最佳方法是什么我可以做到,所以如果其他人使用与现有值相同的值进行插入,它会失败,所以我不必在我的应用程序代码中担心这一点。

4

4 回答 4

295

删除重复项后:

ALTER TABLE dbo.yourtablename
  ADD CONSTRAINT uq_yourtablename UNIQUE(column1, column2);

或者

CREATE UNIQUE INDEX uq_yourtablename
  ON dbo.yourtablename(column1, column2);

当然,在让 SQL Server 尝试插入行并返回异常(异常代价高昂)之前,通常最好先检查此违规行为。

如果您想防止异常冒泡到应用程序,而不对应用程序进行更改,您可以使用INSTEAD OF触发器:

CREATE TRIGGER dbo.BlockDuplicatesYourTable
 ON dbo.YourTable
 INSTEAD OF INSERT
AS
BEGIN
  SET NOCOUNT ON;

  IF NOT EXISTS (SELECT 1 FROM inserted AS i 
    INNER JOIN dbo.YourTable AS t
    ON i.column1 = t.column1
    AND i.column2 = t.column2
  )
  BEGIN
    INSERT dbo.YourTable(column1, column2, ...)
      SELECT column1, column2, ... FROM inserted;
  END
  ELSE
  BEGIN
    PRINT 'Did nothing.';
  END
END
GO

但是如果你不告诉用户他们没有执行插入,他们会想知道为什么数据不存在并且没有报告异常。


这里的编辑是一个完全符合您要求的示例,即使使用与您的问题相同的名称,也可以证明这一点。在假设上述想法只处理一列或另一列而不是组合之前,您应该尝试一下......

USE tempdb;
GO

CREATE TABLE dbo.Person
(
  ID INT IDENTITY(1,1) PRIMARY KEY,
  Name NVARCHAR(32),
  Active BIT,
  PersonNumber INT
);
GO

ALTER TABLE dbo.Person 
  ADD CONSTRAINT uq_Person UNIQUE(PersonNumber, Active);
GO

-- succeeds:
INSERT dbo.Person(Name, Active, PersonNumber)
  VALUES(N'foo', 1, 22);
GO

-- succeeds:
INSERT dbo.Person(Name, Active, PersonNumber)
  VALUES(N'foo', 0, 22);
GO

-- fails:
INSERT dbo.Person(Name, Active, PersonNumber)
  VALUES(N'foo', 1, 22);
GO

在所有这些之后表中的数据:

ID   Name   Active PersonNumber
---- ------ ------ ------------
1    foo    1      22
2    foo    0      22

最后插入的错误消息:

消息 2627,级别 14,状态 1,第 3 行违反 UNIQUE KEY 约束“uq_Person”。无法在对象“dbo.Person”中插入重复键。该语句已终止。

此外,我最近还写了一篇关于以任一顺将唯一约束应用于两列的解决方案的博客:

于 2013-04-03T23:56:18.293 回答
19

这也可以在 GUI 中完成:

  1. 在“人员”表下,右键单击索引
  2. 单击/悬停新索引
  3. 单击非聚集索引...

在此处输入图像描述

  1. 将给出默认索引名称,但您可能需要更改它。
  2. 选中唯一复选框
  3. 单击添加...按钮

在此处输入图像描述

  1. 检查要包含的列

在此处输入图像描述

  1. 在每个窗口中单击确定。
于 2016-08-18T15:21:34.843 回答
4

在我的情况下,我需要允许许多不活动并且只有两个键的一个组合活动,如下所示:

UUL_USR_IDF  UUL_UND_IDF    UUL_ATUAL
137          18             0
137          19             0
137          20             1
137          21             0

这似乎有效:

CREATE UNIQUE NONCLUSTERED INDEX UQ_USR_UND_UUL_USR_IDF_UUL_ATUAL
ON USER_UND(UUL_USR_IDF, UUL_ATUAL)
WHERE UUL_ATUAL = 1;

这是我的测试用例:

SELECT * FROM USER_UND WHERE UUL_USR_IDF = 137

insert into USER_UND values (137, 22, 1) --I CAN NOT => Cannot insert duplicate key row in object 'dbo.USER_UND' with unique index 'UQ_USR_UND_UUL_USR_IDF_UUL_ATUAL'. The duplicate key value is (137, 1).
insert into USER_UND values (137, 23, 0) --I CAN
insert into USER_UND values (137, 24, 0) --I CAN

DELETE FROM USER_UND WHERE UUL_USR_ID = 137

insert into USER_UND values (137, 22, 1) --I CAN
insert into USER_UND values (137, 27, 1) --I CAN NOT => Cannot insert duplicate key row in object 'dbo.USER_UND' with unique index 'UQ_USR_UND_UUL_USR_IDF_UUL_ATUAL'. The duplicate key value is (137, 1).
insert into USER_UND values (137, 28, 0) --I CAN
insert into USER_UND values (137, 29, 0) --I CAN
于 2020-05-14T17:01:47.003 回答
0

如果您有很多插入查询但不想每次都发出错误消息,您可以这样做:

CREATE UNIQUE NONCLUSTERED INDEX SK01 ON dbo.Person(ID,Name,Active,PersonNumber) 
WITH(IGNORE_DUP_KEY = ON)

在此处输入图像描述

于 2020-02-01T06:04:07.837 回答