问题
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:
- I make sure they are in correct order
- I shift bytes of 32 bits to left (so just by multiplying 4294967296 i get what i want)
- 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