2012-07-04 34 views
9

Tôi có bảng OrderLines (OrderID int, LineIndex int,) và tham số có giá trị bảng của cùng một cấu trúc xác định các dòng đơn đặt hàng mới cho một đơn đặt hàng.TSQL - tuyên bố MERGE với khóa tổng hợp

Vì vậy, nếu tôi đã có OrderLines sau

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

và TVP sau

1001 1 yogurt 

Tôi muốn nhận được OrderLines sau

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

Tức là chỉ chạm vào các hàng cho một Đơn đặt hàng.

Vì vậy, tôi đã viết truy vấn của tôi như thế này

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; 

và nó sẽ xoá tất cả OrderLines khác (không được đề cập) cho đơn đặt hàng khác.

tôi đã cố gắng

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

nhưng có một lỗi cú pháp.

Tôi nên viết lại truy vấn của mình như thế nào?

Trả lời

11

Chỉ cần sử dụng các tập con có liên quan của OrderLines như một mục tiêu:

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 để kiểm tra.

1

Để bắt đầu, chỉ các cột từ bảng mục tiêu mới có thể được sử dụng trong điều kiện hợp nhất bổ sung WHEN NOT MATCHED BY SOURCE (đó là trên MSDN).

Và tôi nghĩ rằng bạn sẽ mất tất cả các mục nhập thừa từ bảng mục tiêu, vì chúng không khớp với bất kỳ thứ gì trong nguồn.

Bạn nên viết lại truy vấn của mình trước tiên bằng cách xóa mệnh đề WHEN NOT MATCHED BY SOURCE và sau đó xóa các hàng thừa/không cần thiết riêng biệt.

Sau đó, bạn cần phải nhận được tất cả các mục được cập nhật hoặc chèn vào trong bảng mục tiêu bằng cách thêm:

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 

Bây giờ trong @OutputTable bạn có tất cả các phím mà một trong hai đã được cập nhật hoặc nhập vào bảng mục tiêu (thông báo mệnh đề OUTPUT).

Bạn chỉ cần bây giờ để xem những hàng từ bảng mục tiêu, mà chỉ phù hợp với các phím từ @OrderLines, không nằm trong tuyên bố @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 

Những gì bạn đang làm gì ở đây (nghĩ nó đúng) thực sự là những gì bạn muốn xóa ngay từ đầu. Kết nối bên trong lọc kết quả được đặt thành @OrderLines (vì vậy chỉ có các hàng bằng các khóa đó) và bên trái nối với mệnh đề where đang thực hiện một phép nối chống bán, để nhận các hàng trong bảng đích mà không bị ảnh hưởng bởi câu lệnh MERGE (chèn hoặc cập nhật) nhưng vẫn có các phím nằm trong bảng nguồn (@OrderLines).

Nên đúng ... Hãy cho tôi biết sau khi bạn kiểm tra.

Bạn có thể muốn bọc tất cả điều này (MERGE + DELETE) bên trong một giao dịch, nếu bạn quyết định đi theo phương pháp này.

Các vấn đề liên quan