2013-04-25 2 views
1

나는 두 테이블 (간체)가 트럭에 예고편이 전혀 없거나 예고편이 하나 있거나 두 가지 trai가있을 수 있습니다. lers.SQL 고유 인덱스

동일한 TrailerID를 두 번 사용할 수 없도록 Trucks 테이블에 인덱스를 만들려면 어떻게해야합니까?

한 트레일러, 나는 계산 필드

IsNull(TrailerID, -1 * TruckID) 

를 작성하고이 고유 인덱스를 만들 수 있습니다. 하지만 두 개의 예고편을 관리하려면 어떻게해야합니까?

답변

1

나는 색인만으로 이것을 할 수 있다고 생각하지 않는다. 당신은 당신의 신원을 가지고 있어야합니다. 난 당신이 위반이 trailerID 트리거

당신은 여전히해야 인덱스에 대해 하나

Select Trailer1 FROM Trucks 
UNION 
Select Trailer2 FROM Trucks 

http://msdn.microsoft.com/en-gb/library/ms189799%28v=sql.105%29.aspx에 존재하지 않는 것을 보장 할 발생하면 롤백하기 위해 업데이트에 대한 트리거를 impliment해야합니다 생각 Trailer1과 Trailer2 둘 다에서 실행되므로 TrailerID가 두 열에 모두 존재하면 옵티마이 저는 조회 할 수 있습니다.

+0

동의합니다. 업데이트 또는 삽입을 시도하기 전에 먼저 Select 문을 실행하여 예고편이 있는지 확인하기 위해 SP를 작성하는 것이 더 쉽습니다. 하지만 인덱스를 사용하여 우아한 솔루션을 찾고있었습니다. – navigator

+0

글쎄, 디버깅하기가 매우 어려울 수 있기 때문에 나는 트리거를 좋아하지 않는다. union에 대한 뷰를 생성 한 다음 결과 컬럼을 고유하게 만들 수 있어야합니다. (후드 아래에서 트리거가 발생할 것으로 의심됩니다.) http://msdn.microsoft.com/en-us/library/aa933148%28v=sql.80%29.aspx이게 작동 할 것이라고 제안합니다 –

+0

@IanP : UNION에 인덱스 된 뷰를 생성 할 수 없습니다. – Quassnoi

0

Traileid1과 TrailerId2에 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), 
) 
+2

나는 OP가'Trailer2'에 나타나지 않는'Trailer1'에 나타난 값을 방지하려고 시도하고 있다고 생각합니다. (반대의 경우도 마찬가지입니다) –

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를 참조하십시오.

+0

간단한 작업을 위해 불필요한 복잡성이 많이 발생하는 것처럼 보입니다. 더 간단한 방법이 있습니까? – navigator

+1

@arjun : 어떻게 생각하세요? 더 간단한 방법이 있다면, 제가 복잡한 것을 제안하겠습니까? – Quassnoi

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 값으로 제한하거나 (또는 ​​enum을 사용) TruckID 및 TrailerNo에 고유 인덱스를 추가 할 수 있습니다. 이렇게하면 3 개 이상의 트레일러를 트럭에 추가 할 수 없습니다. 필요한 경우 제약 조건을 확장 할 수 있습니다 (기차의 경우 f.ex.).

이것은 문제를 해결하기 위해 제안 된 방법입니다. 그러면 정규화 된 데이터베이스를 얻을 수 있습니다.

그러나 많은 이유에서 항상 가능하지는 않습니다.

+0

예. 이것은 새로운 프로젝트를위한 확실한 탈출구 였을 것입니다. 불행히도 현재로서는 다 대다 관계를 만드는 것이 선택 사항이 아닙니다. 그것은 응용 프로그램의 다른 부분에 많은 SQL을 복잡하게합니다. 어쨌든 고마워! – navigator