Unique constraint on two columns regardless of order

两盒软妹~` 提交于 2019-12-07 13:02:57

问题


I have the following table definition:

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)
)

I want the two Color columns to be unique, regardless of the combination they appear in.

E.g. attemping:

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

but then trying the same after that first record exists with the colors reversed should fail:

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

I have this problem solved using high-level code, but I'd rather the constraint be enforced directly in the database, preferably without involving things like triggers.

Thanks.


回答1:


You could maybe create computed column, something like:

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)
)

UPDATE (You should test it before, i did just very quick testing)

Idea:

Integer is 4 byts. If i put 2 integers together- i get 8 bytes. If i order them- i get unique BigInt value (8 bytes).

So what i do:

  1. I make sure they are in correct order
  2. I shift bytes of 32 bits to left (so just by multiplying 4294967296 i get what i want)
  3. I make logical OR- so i get 8 byte BigInt value, that should always be unique!

So:

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:


Avoid the problem entirely by putting in a constraint to require that SecondColorID >= FirstColorID. It creates a limitation on what can go into the database that goes a bit beyond what you're looking for. But that extra requirement will be useful down the line if you want to query for a certain color pattern, because you can just look for SecondColorID = 1 AND FirstColorID = 2 rather than having to write extra logic to account for the two color IDs having an unpredictable ordering.

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);



回答3:


Create computed columns, so that ComputedFirstColorID is the lower of FirstColorID and SecondColorID, and ComputedSecondColorID is the higher of FirstColorID and SecondColorID. Now the index

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

Should be fine.




回答4:


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

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



来源:https://stackoverflow.com/questions/11414976/unique-constraint-on-two-columns-regardless-of-order

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!