대안

2012-03-17 6 views
3

그래서 내가 두 개의 테이블이 뷰에서 제약 조건을 확인 ?대안

체크 제약 조건은보기에서 허용되지 않습니다. SQL 서버를 2008

편집을 사용하여 :

이는 this question에 대한 후속 질문입니다.

비즈니스 규칙 :

  1. 같은 요청이 여러 사용자에게 전달할 수 있습니다. 따라서 ForwardedRequests 테이블의 Id 열.

  2. 사용자는 특정 RequestScheme에 대해 하나의 요청 만 수신 할 수 있습니다. 그래서 요청 테이블에 RequestSchemeId + ReceivedByUserId에 대한 UniqueKey 제약 조건을 만들었습니다.

  3. 전달 된 사용자가 다른 사용자의 동일한 구성표에서 전달 된 요청을 아직 갖고 있지 않은 경우에만 요청을 다른 사용자에게 전달할 수 있습니다. 마틴이 linked question에서 제안한 것처럼 두 테이블에서 뷰를 만들고 Requests.RequestSchemeId + ForwardedRequests.ForwardedToUserId에 고유 한 제약 조건을 추가했습니다.

  4. 이 질문에 대한 비즈니스 규칙은 요청의 수신자가 자신에게 전달할 수 없다는 것입니다.

+1

왜 'WHERE Requests.ReceivedByUserId <> ForwardedRequests.ReceivedByUserId'를 사용하지 않습니까? – Kaf

+1

@ 카프 - 그건 도움이되지 않습니다. [질문의 추가 컨텍스트는 여기에 있습니다] (http://stackoverflow.com/q/9749902/73226) –

+0

@Martin 링크를 추가해 주셔서 감사합니다. – NVM

답변

5

SQL Server에서이 문제를 해결할 수있는 몇 가지 방법을 생각해 볼 수 있습니다. 둘 다 꽤 해키하지만 다른 접근법을 보는 데 관심이 있습니다.

1) 1/(ForwardedToUserId - ReceivedByUserId) AS FailIfSame이라는 추가 열 ForwardedRequestsInRequestSchemes을 추가하면 두 값이 같을 경우 Divide by zero error가됩니다. 이것은 인덱싱 된 뷰에 중복 된 열을 저장하는 것을 의미합니다.

2) 두 행 테이블에 교차 결합 된 이러한 행을 반환 한 다음 해당 뷰에 고유 제한 조건을 정의하는 새보기를 만들 수 있습니다. 이보기는 항상 비어 있습니다.

CREATE TABLE dbo.TwoRows(C INT) INSERT INTO dbo.TwoRows VALUES(1),(1) 

GO 

CREATE VIEW dbo.FailIfForwardedUserEqualToReceivedByUser 
WITH SCHEMABINDING 
AS 
    SELECT 1 AS C 
    FROM dbo.ForwardedRequests FR 
     INNER JOIN dbo.Requests R 
      ON R.Id = FR.RequestId AND R.ReceivedByUserId = FR.ForwardedToUserId 
     CROSS JOIN dbo.TwoRows 

GO 

CREATE UNIQUE CLUSTERED INDEX ix ON 
    dbo.FailIfForwardedUserEqualToReceivedByUser(C) 
+0

AFAIK 교차 조인은 인덱싱 가능보기에서 허용되지 않습니다. –

+0

@VitaliyKalinin - 그렇습니다. 필자는이 테스트를 통해 SQL Server가 요구 사항을 적용하도록했습니다. –

+0

실제로 당신 말이 맞습니다. –

3

한 가지 방법은 테이블에 update, insert, delete 권한을 허용하고, 저장 프로 시저를 사용하여 비즈니스 요구 사항을 적용하는 것입니다. 예 :

create procedure dbo.AddRequestForward(
    @requestId int 
, @forwardedToUserId int) 
as 
insert ForwardedRequests 
     (ForwardedRequests, ForwardedRequests) 
select @requestId 
,  @forwardedToUserId 
where not exists 
     (
     select * 
     from Requests 
     where Id = @requestId 
       and @forwardedToUserId = @forwardedToUserId 
     ) 

if @@rowcount = 0 
    return -1 -- Forwarded and Received identical user 
return 1 -- Success 
go 
+2

추가 잠금 힌트가 없으면이 경쟁 조건이 있습니다. 따라서 SQL Server에서 이러한 제약 조건을 적용하는 것이 일반적으로 더 좋습니다. –

+0

@MartinSmith : 질문이 많은 양의 동시 트래픽을 지정하지 않는 한, 이것이 충분히 안전하다고 생각합니다. – Andomar

+1

@Andomar "안전함"은 무서운 것으로 들립니다. 필자는 데이터베이스 프로그래밍에 익숙하지 않지만 절대 잘못하지는 않을 것이므로 마틴의 * 못생긴 접근법을 사용하는 것이 현명 할 것이라고 생각합니다. – NVM