将唯一约束添加到两列的组合

leo*_*ora 133 sql sql-server

我有一张桌子,不知何故,同一个人Person两次进入我的桌子.现在,主键只是一个自动编号,但还有两个其他字段存在,我想强制它们是唯一的.

例如,字段是:

ID  
Name  
Active  
PersonNumber  
Run Code Online (Sandbox Code Playgroud)

我只想要一个具有唯一PersonNumber且Active = 1的记录.
(因此两个字段的组合必须是唯一的)

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

Aar*_*and 199

删除副本后:

ALTER TABLE dbo.yourtablename
  ADD CONSTRAINT uq_yourtablename UNIQUE(column1, column2);
Run Code Online (Sandbox Code Playgroud)

要么

CREATE UNIQUE INDEX uq_yourtablename
  ON dbo.yourtablename(column1, column2);
Run Code Online (Sandbox Code Playgroud)

当然,在让SQL Server尝试插入行并返回异常(异常很昂贵)之前,首先检查此违规通常会更好.

http://www.sqlperformance.com/2012/08/t-sql-queries/error-handling

http://www.mssqltips.com/sqlservertip/2632/checking-for-potential-constraint-violations-before-entering-sql-server-try-and-catch-logic/

如果要防止异常冒泡到应用程序,而不更改应用程序,可以使用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
Run Code Online (Sandbox Code Playgroud)

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


编辑这里是一个例子,它正是你要求的,甚至使用与你的问题相同的名称,并证明它.在假设上述想法只处理一列或另一列而不是组合之前,你应该尝试一下......

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
Run Code Online (Sandbox Code Playgroud)

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

ID   Name   Active PersonNumber
---- ------ ------ ------------
1    foo    1      22
2    foo    0      22
Run Code Online (Sandbox Code Playgroud)

最后一个插入的错误消息:

Msg 2627,Level 14,State 1,Line 3违反UNIQUE KEY约束'uq_Person'.无法在对象'dbo.Person'中插入重复键.该语句已终止.

  • @leora是的,我很确定我的答案涉及两个*列*的唯一性. (2认同)
  • 并不是每列必须是唯一的,它的组合(连接)必须是唯一的.那有意义吗 .. (2认同)

Ton*_* L. 11

这也可以在GUI中完成:

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

在此输入图像描述

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

在此输入图像描述

  1. 检查要包含的列

在此输入图像描述

  1. 在每个窗口中单击" 确定"

  • @Faisal 关闭您为该表打开的结果/设计窗口,然后重试。 (7认同)
  • 什么都没有,请参阅此文章以供参考:https://blog.sqlauthority.com/2007/04/26/sql-server-difference-between-unique-index-vs-unique-constraint/ (2认同)

小智 5

就我而言,我需要允许许多不活动键,并且仅允许两个键的一种组合处于活动状态,如下所示:

UUL_USR_IDF  UUL_UND_IDF    UUL_ATUAL
137          18             0
137          19             0
137          20             1
137          21             0
Run Code Online (Sandbox Code Playgroud)

这似乎有效:

CREATE UNIQUE NONCLUSTERED INDEX UQ_USR_UND_UUL_USR_IDF_UUL_ATUAL
ON USER_UND(UUL_USR_IDF, UUL_ATUAL)
WHERE UUL_ATUAL = 1;
Run Code Online (Sandbox Code Playgroud)

这是我的测试用例:

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
Run Code Online (Sandbox Code Playgroud)