无论顺序如何,两列都有唯一约束

时间:2012-07-10 13:59:20

标签: sql-server unique-constraint

我有以下表格定义:

CREATE TABLE [Car] 
(
   CarID int NOT NULL PRIMARY KEY IDENTITY(1,1),
   FirstColorID int FOREIGN KEY REFERENCES Colors(ColorID),
   SecondColorID int FOREIGN KEY REFERENCES Colors(ColorID),

   UNIQUE(FirstColorID, SecondColorID)
)

我希望两个Color列都是唯一的,无论它们出现在哪种组合中。

E.g。 attemping:

INSERT INTO Car (FirstColorID, SecondColorID) VALUES (1, 2); --should succeed

但是在第一条记录存在之后尝试相同的颜色反转应该会失败:

INSERT INTO Car (FirstColorID, SecondColorID) VALUES (2, 1); --should violate constraint/check

我使用高级代码解决了这个问题,但我宁愿直接在数据库中强制执行约束,最好不要涉及触发器之类的东西。

感谢。

4 个答案:

答案 0 :(得分:2)

通过设置要求SecondColorID >= FirstColorID的约束来完全避免问题。它会对可以进入数据库的内容产生限制,这有限超出了您的需求。但是如果你想要查询某种颜色模式,那么这个额外的要求将非常有用,因为你可以只查找SecondColorID = 1 AND FirstColorID = 2,而不必编写额外的逻辑来解释具有不可预测排序的两个颜色ID

CREATE TABLE [Car] 
(
   CarID int NOT NULL PRIMARY KEY IDENTITY(1,1),
   FirstColorID int FOREIGN KEY REFERENCES Colors(ColorID),
   SecondColorID int FOREIGN KEY REFERENCES Colors(ColorID),

   UNIQUE(FirstColorID, SecondColorID)
)

ALTER TABLE [Car] WITH CHECK
    ADD CHECK (SecondColorID >= FirstColorID);

答案 1 :(得分:2)

您可以创建计算列,例如:

CREATE TABLE [Car] 
(
   CarID int NOT NULL PRIMARY KEY IDENTITY(1,1),
   FirstColorID int, --FOREIGN KEY REFERENCES Colors(ColorID),
   SecondColorID int, --FOREIGN KEY REFERENCES Colors(ColorID),
   xColor As Cast(Case When FirstColorID > SecondColorID Then FirstColorID Else SecondColorID End as varChar) + ',' + 
        Cast(Case When FirstColorID <= SecondColorID Then SecondColorID Else FirstColorID End as varChar),
   UNIQUE(xColor)
)

更新(您之前应该测试一下,我只是非常快速地进行测试)

<强>观

整数是4个字节。如果我把2个整数放在一起 - 我得到8个字节。如果我订购它们 - 我得到唯一的BigInt值(8字节)。

所以我做了什么:

  1. 我确保它们的顺序正确
  2. 我将32位的字节向左移位(所以只需乘以4294967296我得到我想要的东西)
  3. 我做了逻辑OR-所以得到8字节的BigInt值,它应该总是唯一的!
  4. 所以:

    CREATE TABLE [Car] 
    (
       CarID int NOT NULL PRIMARY KEY IDENTITY(1,1),
       FirstColorID int, --FOREIGN KEY REFERENCES Colors(ColorID),
       SecondColorID int, --FOREIGN KEY REFERENCES Colors(ColorID),
       xColor As 
           Case When FirstColorID > SecondColorID Then 
                Cast(FirstColorID as BigInt) * Cast(4294967296 as BigInt) | Cast(SecondColorID as BigInt)
            Else 
                Cast(SecondColorID as BigInt) * Cast(4294967296 as BigInt) |  Cast(FirstColorID as BigInt)
            End
      UNIQUE(xColor)
    )
    

答案 2 :(得分:0)

CREATE UNIQUE NONCLUSTERED INDEX index_name ON Car (FirstColorID, SecondColorID)

http://msdn.microsoft.com/en-us/library/ms188783.aspx

答案 3 :(得分:0)

创建计算列,以便ComputedFirstColorID是FirstColorID和SecondColorID中的较低者,ComputedSecondColorID是FirstColorID和SecondColorID中的较高者。现在是索引

CREATE UNIQUE NONCLUSTERED INDEX index_name ON Car (ComputedFirstColorID, ComputedSecondColorID)

应该没事。