2012-07-04 2 views
9

테이블 OrderLines (OrderID int, LineIndex int) 및 동일한 order order에 대한 새로운 주문 라인을 정의하는 동일한 구조의 테이블 반환 매개 변수가 있습니다.복합 키가있는 TSQL - MERGE 문

그래서 나는 다음과 같은 OrderLines

1000 1 bread 
1000 2 milk 
1001 1 oil 
1001 2 yogurt 
1002 1 beef 
1002 2 pork 

다음과 같은 TVP이 있다면

1001 1 yogurt 

나는 다음과 같은 OrderLines 싶어

1000 1 bread 
1000 2 milk 
1001 1 yogurt 
1002 1 beef 
1002 2 pork 

즉, 하나의 주문에 대해서만 행을 터치합니다.

그래서 나는이

MERGE 
    [OrderLines] AS [Target] 
USING 
(
    SELECT 
     [OrderID], [LineIndex], [Data] 
    FROM 
     @OrderLines 
) 
AS [Source] ([OrderID], [LineIndex], [Data]) 
ON ([Target].[OrderID] = [Source].[OrderID]) AND ([Target].[LineIndex] = [Source].[LineIndex]) 
WHEN MATCHED THEN 
    UPDATE 
    SET 
     [Target].[Data] = [Source].[Data] 
WHEN NOT MATCHED BY TARGET THEN 
    INSERT 
     ([OrderID], [LineIndex], [Data]) 
    VALUES 
     ([Source].[OrderID], [Source].[LineIndex], [Source].[Data]) 
WHEN NOT MATCHED BY SOURCE THEN 
    DELETE; 

처럼 내 쿼리를 작성하고 다른 주문에 대한 다른 모든 (언급되지 않은) OrderLines을 삭제합니다.

나는
WHEN NOT MATCHED BY SOURCE AND ([Target].[OrderID] = [Source].[OrderID]) THEN 

을 시도하지만 구문 오류가 발생했습니다.

검색어를 어떻게 다시 작성해야합니까?

답변

11

그냥 대상으로 OrderLines의 관련 부분 집합을 사용

WITH AffectedOrderLines AS ( SELECT * FROM OrderLines WHERE OrderID IN (SELECT OrderID FROM @OrderLines) ) 
MERGE 
    AffectedOrderLines AS [Target] 
USING 
(
    SELECT 
     [OrderID], [LineIndex], [Data] 
    FROM 
     @OrderLines 
) 
AS [Source] ([OrderID], [LineIndex], [Data]) 
ON ([Target].[OrderID] = [Source].[OrderID]) AND ([Target].[LineIndex] = [Source].[LineIndex]) 
WHEN MATCHED THEN 
    UPDATE 
    SET 
     [Target].[Data] = [Source].[Data] 
WHEN NOT MATCHED BY TARGET THEN 
    INSERT 
     ([OrderID], [LineIndex], [Data]) 
    VALUES 
     ([Source].[OrderID], [Source].[LineIndex], [Source].[Data]) 
WHEN NOT MATCHED BY SOURCE THEN 
    DELETE; 

그리고 here's a SQL Fiddle 테스트 할 수 있습니다.

1

우선 대상 테이블의 열만 WHEN NOT MATCHED BY SOURCE 병합 조건 (MSDN에 있음)에서 사용할 수 있습니다.

그리고 원본 테이블의 모든 항목과 일치하지 않으므로 대상 테이블에서 모든 추가 항목을 잃어버린다는 것은 정상적인 현상이라고 생각합니다.

먼저 WHEN NOT MATCHED BY SOURCE 절을 삭제 한 다음 추가/불필요한 행을 개별적으로 삭제하여 쿼리를 다시 작성해야합니다.

그런 다음 추가 업데이트 또는 목표 테이블에 삽입되는 모든 항목을 얻을 필요가 : @OutputTable 당신도 목표 테이블에 업데이트되거나 입력 된 모든 키가 (고지에서 현재

DECLARE @OutputTable table(OrderId INT, OrderLine INT); 

...Your entire MERGE 
WHEN NOT MATCHED BY TARGET THEN 
    INSERT 
     ([OrderID], [LineIndex], [Data]) 
    VALUES 
     ([Source].[OrderID], [Source].[LineIndex], [Source].[Data]) 
OUTPUT INSERTED.OrderId, INSERTED.LineIndex INTO @OutputTable 

OUTPUT 절). 당신은 단지에만 @OrderLines에서 키와 일치하는 목표 테이블에서 행을보기 위해 지금 필요한

는)이 @OutputTable' and delete them (so they haven't been updated nor inserted by the MERGE` 문에없는 :

DELETE A 
FROM [OrderLines] AS A 
INNER JOIN @OrderLines AS B 
ON B.OrderId = A.OrderId AND B.LineIndex = A.LineIndex 
LEFT OUTER JOIN @OutputTable AS C 
ON C.OrderId = A.OrderId AND C.OrderLine = A.LineIndex 
WHERE C.OrderId IS NULL AND C.OrderLine IS NULL 

당신이 여기서 뭘하고 (생각 그것은 맞습니다) 실제로 당신이 처음에 삭제하고 싶었던 것입니다. 내부 조인은 결과 집합을 @OrderLines (그 키를 가진 행만 포함)으로 필터링하고 where 조인과 함께 왼쪽 조인은 안티 세미 조인을 수행하여 MERGE 문 (삽입 또는 삭제)의 영향을받지 않는 대상 테이블의 행을 가져옵니다. 업데이트) 하지만 여전히 소스 테이블 (@OrderLines)에있는 키가 있습니다.

맞아야합니다 ... 테스트 한 후에 알려주세요.

이 접근 방식을 사용하기로 결정한 경우 트랜잭션 내에서이 모든 내용 (MERGE + DELETE)을 래핑 할 수 있습니다.

관련 문제