2016-01-24 19 views
5

Zajmuję się wieloma opcjami typu CRUD i tworzeniem scalonych przechowywanych plików z CUD. My przechowywane proc wygląda toDlaczego WHEN MATCHED "nie może pojawić się więcej niż jeden raz w klauzuli" UPDATE "instrukcji 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; 

Kiedy idę do wykonania tego otrzymuję ten Full Error

Msg 10714, Level 15, State 1, Procedura usp_AdministrationHistoryMerge, Linia 36 Działanie typu "WHEN MATCHED" nie może pojawić się więcej niż jeden raz w klauzuli "UPDATE" instrukcji MERGE.

Rozejrzałem się po SO i znalazłem kilka sposobów rozwiązania tego problemu, ale to, co znalazłem, nie jest odpowiednim rozwiązaniem dla tego błędu, ponieważ zamiast usuwania i muszę zaktualizować IsActive rekordu do 0.

Ponadto, w moich poszukiwań nikt tak naprawdę nie wyjaśnia, dlaczego ten błąd jest rzucany, tak, wiem, że jest to oczywiste, ponieważ błąd jest właśnie tutaj, ale dlaczego nie jest to dozwolone? i na tej podstawie są jakieś pomysły, jak to osiągnąć? lub powinienem mieć to połączenie połączyć inny storedproc, gdy @Action jest 0?

+0

Czy jesteś przekonany, że chcesz użyć "MERGE"? https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ –

+3

Jest to wyraźnie określone w [dokumentacji MERGE] (https://msdn.microsoft.com /en-us/library/bb510625.aspx): * Instrukcja MERGE może zawierać co najwyżej dwie klauzule WHEN MATCHED. * ** i ** * Jeśli istnieją dwie klauzule WHEN MATCHED, należy określić akcję UPDATE, a należy określić akcję DELETE.* –

+0

@AaronBertrand, To nie był mój wybór, aby użyć MERGE, myślę, że użycie CASE lub instrukcji IF byłoby lepszym wyborem ... Przyjemny artykuł przy okazji – Chris

Odpowiedz

5

W swoim oświadczeniu MERGE, masz trzy WHEN MATCHED klauzule

  • Dwa z UPDATE rachunku
  • Jeden z oświadczeniem INSERT.

Jest to jednak zabronione. jest to wyraźnie stwierdzone w Documentation on MERGE:

Oświadczenie MERGE może mieć co najwyżej dwa WHEN MATCHED klauzul.

I

Jeśli istnieją dwa WHEN MATCHED klauzule, następnie trzeba określić działania UPDATE i trzeba określić DELETE działania.

Również ważne jest, aby wiedzieć, to:

Jeśli UPDATE jest określona w <merge_matched> klauzuli, a więcej niż jednym rzędem <table_source> pasuje do wiersza w target_table podstawie <merge_search_condition>, SQL Serwer zwraca błąd. Instrukcja MERGE nie może aktualizować tego samego wiersza więcej niż raz, ani aktualizować i usuwać tego samego wiersza.