我有两张桌子(简化版) - 卡车和预告片
货车
TruckID int identity
Trailer1 int null
Trailer2 int null
拖车
TrailerID int identity
由于拖车外键可以为空,因此卡车可以根本没有拖车,有一辆拖车或有两辆拖车。
如何在Trucks表上构建索引以确保永远不会使用相同的TrailerID两次?
对于一个预告片,我可以创建一个计算字段
IsNull(TrailerID, -1 * TruckID)
并为此创建一个唯一索引。但是我如何为两个预告片管理这个?
答案 0 :(得分:2)
您需要创建一个有效联合预告片的索引视图。
为此,您必须创建一个微小的支持表:
CREATE TABLE place (id INT NOT NULL PRIMARY KEY)
INSERT
INTO place
VALUES (1),
(2)
GO
CREATE VIEW
v_truck_trailers
WITH SCHEMABINDING
AS
SELECT t.id AS truckId,
p.id AS placeId,
CASE p.id WHEN 1 THEN trailer1 WHEN 2 THEN trailer2 END AS trailerId
FROM dbo.truck t
JOIN dbo.place p
ON CASE p.id WHEN 1 THEN trailer1 WHEN 2 THEN trailer2 END IS NOT NULL
GO
CREATE UNIQUE CLUSTERED INDEX
ux_v_truck_trailers_truck_place
ON v_truck_trailers (truckId, placeId)
GO
CREATE UNIQUE INDEX
ux_v_truck_trailers_trailer
ON v_truck_trailers (trailerId)
GO
现在让我们试一试:
INSERT
INTO truck
VALUES (1, 1, NULL) -- succeeds
INSERT
INTO truck
VALUES (2, 2, 3) -- also succeeds
INSERT
INTO truck
VALUES (3, NULL, 2) -- fails as trailer 2 is already used on truck 2, even if on another place.
请参阅SQLFiddle。
答案 1 :(得分:1)
我不认为你可以单独使用索引来做到这一点。你需要拥有自己的身份。我认为如果发生违规,你必须在你的更新中触发一个触发器以将其回滚,这将确保在任何一个中都不存在trailerID
Select Trailer1 FROM Trucks
UNION
Select Trailer2 FROM Trucks
http://msdn.microsoft.com/en-gb/library/ms189799%28v=sql.105%29.aspx触发器
您仍然应该在Trailer1和Trailer2上都有索引,以便优化器可以查看TralerID是否存在于任一列中。
答案 2 :(得分:1)
如果您可以更改表格结构,我会推荐第三张表TrailersTrucks
TrailersTrucks
TrailersTrucksID int identity
TruckID int not null
TrailerID int not null
[TrailerNo int] - optional
更改卡车声明
Trucks
TruckID int identity
TrailersTrucksID int null
然后您可以在TrailerID上使用唯一索引。您可能还想引入TrailerNo并将其约束为1和2值(或使用枚举)以及在TruckID和TrailerNo上添加唯一索引......这样就不可能将3个或更多拖车添加到卡车中......你如果需要,可以随时扩展约束(f.ex. for train)。
这是解决问题的建议方法,然后你会得到规范化的数据库。
但是我知道并不总是有很多原因:)
答案 3 :(得分:0)
您可以分别对Trailer Id1和Trailer Id2设置UNIQUE约束。
CREATE TABLE Trailers
(
TrailerID int identity PRIMARY KEY NOT NULL,
t_type varchar(10) null
)
CREATE TABLE Trucks
(
TruckID int identity PRIMARY KEY NOT NULL,
Trailer1 int UNIQUE null,
Trailer2 int UNIQUE null
FOREIGN KEY ( Trailer1 ) REFERENCES Trailers(TrailerID),
FOREIGN KEY ( Trailer2 ) REFERENCES Trailers(TrailerID),
)