我有两张桌子(简化的)--卡车和拖车
卡车
TruckID int identity
Trailer1 int null
Trailer2 int null
拖车
TrailerID int identity
由于拖车外键是空的,卡车可以没有拖车,也可以有一辆拖车,或者有两辆拖车。
我如何在卡车表上建立一个索引,以确保同一个TrailerID永远不会被使用两次?
对于一个预告片,我可以创建一个计算字段
IsNull(TrailerID, -1 * TruckID)
并在此基础上创建唯一的索引。但我该怎么处理两辆拖车呢?
发布于 2013-04-25 08:57:26
您将需要创建一个索引视图,这将有效地结合拖车。
为此,您必须创建一个小型支撑表:
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。
发布于 2013-04-25 08:03:15
我认为单靠索引是无法做到这一点的。你需要有你自己的身份。我认为,如果发生违规行为,则必须在更新中插入触发器,以回滚该触发器,这将确保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上都有索引,这样优化器就可以在任何一列中查找TrailerID。
发布于 2013-04-25 09:02:25
如果可以更改表结构,我建议使用第三个表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 )。为了火车)。
这是解决问题的建议方法,然后您将得到规范化的数据库。
然而,我知道这并不总是可能的,原因有很多:)
https://stackoverflow.com/questions/16209015
复制相似问题