2016-01-24 9 views
5

Tôi đang tham gia một loạt các ý kiến ​​của CRUD và tạo các bản lưu trữ hợp nhất khỏi CUD. proc lưu trữ của tôi trông như thế nàyTại sao WHEN MATCHED 'không thể xuất hiện nhiều hơn một lần trong mệnh đề' CẬP NHẬT 'của tuyên bố MERGE?

CREATE PROCEDURE usp_AdministrationHistoryMerge 
    @AdministrationHistoryID int out, 
    @AdministratorID int, 
    @DateCreated datetime, 
    @CreatedBy nvarchar(50), 
    @ModifiedBy nvarchar(50), 
    @Action int 
AS 

SET NOCOUNT OFF 
SET TRANSACTION ISOLATION LEVEL READ COMMITTED 

DECLARE @ERROR_SEVERITY int, 
     @MESSAGE varchar(1000), 
     @ERROR_NUMBER int, 
     @ERROR_PROCEDURE nvarchar(200), 
     @ERROR_LINE int, 
     @ERROR_MESSAGE nvarchar(4000), 
     @IsActive bit, 
     @DateModified datetime; 
begin try 
    if @Action = 1 
     begin 
      set @IsActive = 1 
      set @AdministrationHistoryID = SCOPE_IDENTITY() 
     end 
    merge [AdministrationHistory] as target 
    using (select @AdministratorID, @DateCreated, @CreatedBy, @DateModified, @ModifiedBy, @IsActive) 
    as source (AdministratorID, DateCreated, CreatedBy, DateModified, ModifiedBy, IsActive) 
    on (target.AdministrationHistoryID = source.AdministrationHistoryID) 
    when matched and @Action = -1 then 
     update 
      set IsActive = 0 
    when matched and @Action = 0 then 
     update 
     set ModifiedBy = @ModifiedBy, 
     DateModified = GETDATE() 
    when matched and @Action = 1 then 
    insert 
    (AdministratorID, DateCreated, CreatedBy, IsActive) 
    values 
    (@AdministratorID, @DateCreated, @CreatedBy, @IsActive); 
end try 

BEGIN CATCH 
    SET @ERROR_SEVERITY = ISNULL(ERROR_SEVERITY(),''); 
    SET @ERROR_NUMBER = ISNULL(ERROR_NUMBER(),''); 
    SET @ERROR_PROCEDURE = ISNULL(ERROR_PROCEDURE(),''); 
    SET @ERROR_LINE = ISNULL(ERROR_LINE(),''); 
    SET @ERROR_MESSAGE = ISNULL(ERROR_MESSAGE(),''); 

    -- Test if the transaction is uncommittable. 
    IF (XACT_STATE()) = -1 
     BEGIN 
      --PRINT N'The transaction is in an uncommittable state. Rolling back transaction.' 
      ROLLBACK TRANSACTION; 
     END; 

    -- Test if the transaction is active and valid. 
    IF (XACT_STATE()) = 1 
     BEGIN 
      --PRINT N'The transaction is committable. Committing transaction.' 
      COMMIT TRANSACTION; 
     END; 

    SET @MESSAGE = 'Error Occured in Stored Procedure ' + cast(@ERROR_PROCEDURE as varchar(200)) + 
        '; Line Number ' + cast(@ERROR_LINE as varchar) + 
        '; Message: [' + cast(@ERROR_NUMBER as varchar) + '] - ' 
        + cast(@ERROR_MESSAGE as varchar(255)) 

    RAISERROR(@MESSAGE, @ERROR_SEVERITY, 1); 
END CATCH; 

Khi tôi đi đến thực hiện điều này tôi nhận được lỗi đầy đủ này

Msg 10.714, Level 15, State 1, Thủ tục usp_AdministrationHistoryMerge, Line 36 Một hành động của loại 'WHEN MATCHED' không thể xuất hiện nhiều hơn một lần trong mệnh đề 'CẬP NHẬT' của câu lệnh MERGE.

Tôi đã xem xét trên SO và tìm thấy một số cách để giải quyết vấn đề này, nhưng những gì tôi đã tìm thấy không phải là giải pháp phù hợp cho lỗi này, thay vì xóa và tôi cần cập nhật IsActive của bản ghi thành 0.

Ngoài ra, trong tìm kiếm của tôi, không ai thực sự giải thích tại sao lỗi này được ném ra, vâng tôi biết rõ ràng vì lỗi ở ngay đó, nhưng tại sao điều này không được phép xảy ra? và dựa trên hoàn cảnh này có ý tưởng nào về cách thực hiện điều này không? hoặc tôi có nên hợp nhất này gọi một storedproc khác khi @Action là 0?

+0

Bạn có chắc chắn muốn sử dụng 'MERGE' không? https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ –

+3

Nó được ghi rõ trong [tài liệu về MERGE] (https://msdn.microsoft.com /en-us/library/bb510625.aspx): * Câu lệnh MERGE có thể có tối đa hai mệnh đề WHCH MATCHED. * ** và ** * Nếu có hai mệnh đề WHEN MATCHED, thì người ta phải chỉ định một hành động UPDATE và người ta phải chỉ định một hành động DELETE.* –

+0

@AaronBertrand, Nó không phải là lựa chọn của tôi để sử dụng MERGE, tôi hình bằng cách sử dụng một câu lệnh CASE hoặc IF sẽ là lựa chọn tốt hơn ... Bài viết hay nhất theo cách – Chris

Trả lời

5

Trong tuyên bố MERGE của bạn, bạn có ba WHEN MATCHED khoản

  • Hai với một UPDATE tuyên bố
  • Một với một tuyên bố INSERT.

Tuy nhiên, điều đó không được phép. Điều này được nêu rõ trong số Documentation on MERGE:

Tuyên bố MERGE có thể có tối đa hai mệnh đề WHEN MATCHED.

Nếu có hai WHEN MATCHED khoản, sau đó người ta phải xác định một hành động UPDATE và người ta phải xác định một hành động DELETE.

Cũng quan trọng phải biết là:

Nếu UPDATE được quy định trong <merge_matched> khoản, và hơn một dãy <table_source> phù hợp với một hàng trong target_table dựa trên <merge_search_condition>, SQL Máy chủ trả về lỗi. Câu lệnh MERGE không thể cập nhật cùng một hàng nhiều lần hoặc cập nhật và xóa cùng một hàng.

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