SQL唯一索引

时间:2013-04-25 07:40:50

标签: sql-server

我有两张桌子(简化版) - 卡车和预告片

货车

TruckID  int identity
Trailer1 int null
Trailer2 int null

拖车

TrailerID int identity

由于拖车外键可以为空,因此卡车可以根本没有拖车,有一辆拖车或有两辆拖车。

如何在Trucks表上构建索引以确保永远不会使用相同的TrailerID两次?

对于一个预告片,我可以创建一个计算字段

IsNull(TrailerID, -1 * TruckID)

并为此创建一个唯一索引。但是我如何为两个预告片管理这个?

4 个答案:

答案 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),
)