当前位置: 首页 > 知识库问答 >
问题:

为两列的组合添加唯一约束

芮承运
2023-03-14

我有一张桌子,不知怎的,同一个人进了我的person桌子两次。现在,主键只是一个自动编号,但还有两个字段存在,我想强制它们是唯一的。

例如,这些字段是:

ID  
Name  
Active  
PersonNumber  

我只想要一张带有唯一PersonNumber和Active=1的唱片
(因此这两个字段的组合必须是唯一的)

SQL server中现有表的最佳方式是什么?我可以这样做,如果其他任何人使用与现有值相同的值进行插入,则插入失败,因此我不必在应用程序代码中担心这一点。

共有3个答案

麻书
2023-03-14

在我的例子中,我需要允许许多不活动,并且只允许两个键的一个组合处于活动状态,如下所示:

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
宗政斌
2023-03-14

这也可以在GUI中完成:

  1. 在"Person"表下,右键单击[索引]
  2. 点击/悬停新建索引
  3. 点击非聚集索引...
姚俊贤
2023-03-14

删除副本后:

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

或者

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

当然,在让SQL服务器尝试插入行并返回异常(异常代价高昂)之前,首先检查此违规通常会更好。

>

  • 不同错误处理技术对性能的影响

    在输入TRY/CATCH之前检查潜在的约束冲突

    如果要防止异常冒泡到应用程序中,而不更改应用程序,可以使用而不是触发器:

    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
    

    上次插入时出现错误消息:

    Msg 2627,14级,状态1,第3行违反唯一密钥约束“uq_Person”。无法在对象“dbo”中插入重复密钥。“人”。声明已被终止。

    最近我还在博客上写了一个解决方案,可以将唯一约束按任意顺序应用于两列:

    • 在顺序无关紧要的情况下强制执行唯一约束

  •  类似资料:
    • 问题内容: 我一直在尝试找出是否有可能对两列的组合具有唯一约束。 具体来说,我有两列A和B。 我有下面这样的行 然后我希望以下组合在插入时失败 我尝试添加一个简单的约束 但这让我在已经存在时插入。 这可能吗?还是在插入之前必须检查组合是否存在? 问题答案: 您可以使用表达式的索引来执行此操作: 我不认为约束允许表达式(并且现在没有方便的Postgres进行测试),但这本质上是同一回事。

    • 问题内容: 我有三张桌子- 我想确保当它们自然连接时,product_id +文件名是唯一的。到目前为止,我拥有的最佳解决方案是将文件名添加到product_attachment表中,但是我想知道是否有避免这种情况的方法。 问题答案: 如果文件名列不是唯一的,则可以在表上添加自定义约束。请注意,这将在每次插入和更新时执行以下查询,这并不是理想的性能。

    • 问题内容: 我想在我的MySQL表上添加一个唯一性约束。该表包含四列: 此约束必须检查对于new行,new和都未包含在或中。 例子 : 有没有办法定义这样的约束? 问题答案: 您可以通过触发器来做到这一点 注意: 由于您使用的MySQL版本缺少技巧,因此当找到具有相同地址的行时,违反对其中一列的约束。 这是 SQLFiddle 演示。取消注释最后一个插入语句之一,然后单击确定。这些插入不会成功。

    • 我有下表: 我希望KEY_1和KEY_2的组合是唯一的,反之亦然。 这样,我可以使KEY_1和KEY_2之间的组合唯一,但我也希望相反。 示例: 我无法再次插入此值,反之亦然。 这应该是无效的(因为它是同一对密钥): 谢啦

    • 问题内容: 我有一个带有4列的表格 每列将是A,B,C,D 列A是主键。列B具有唯一的名称约束。 现在,我想删除列B的唯一约束,并通过组合列B,C和D给出唯一约束。因此,该表将只允许一行包含列B,C和D中的特定值。 如何给这种约束? 我尝试给复合唯一密钥,例如: 但这是在检查是否存在任何约束,而不是在检查唯一键约束的组合。 问题答案: 在这些列上创建唯一键 Oracle / PLSQL:唯一约束

    • 问题内容: 我有一种情况,我只想在其他字段中有特定值的情况下才添加唯一约束(例如表为ID CategoryName名称值Value CategoryID) 约束将在ID,CategoryName和Name上,只有CategoryID为0 是否有可能? 问题答案: