2016-01-24 7 views
5

Sto prendendo un sacco di operandi CRUD e sto creando un merge memorizzato dal CUD. Il mio proc memorizzato assomiglia a questoPerché WHEN MATCHED 'non può apparire più di una volta in una clausola' UPDATE 'di un'istruzione 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; 

Quando vado a eseguire questo sto ottenendo questo errore completo

Msg 10714, livello 15, stato 1, procedura usp_AdministrationHistoryMerge, Linea 36 Un'azione di tipo 'WHEN MATCHED' non può apparire più di una volta in una clausola 'UPDATE' di un'istruzione MERGE.

Ho guardato in giro su SO e ha trovato un paio di modi per risolvere questo, ma quello che ho trovato non sono soluzioni adatte per questo errore, come invece di un'operazione di eliminazione e ho bisogno di aggiornare IsActive del record a un 0.

Inoltre, nella mia ricerca nessuno spiega veramente perché questo errore viene lanciato, sì, so che è ovvio perché l'errore è proprio lì, ma perché non è permesso che ciò accada? e in base a questa circostanza ci sono delle idee su come realizzarlo? o dovrei avere questa fusione chiamare un altro storedproc quando @Action è 0?

+0

Sei convinto di voler utilizzare 'MERGE'? https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ –

+3

È chiaramente indicato nella [documentazione su MERGE] (https://msdn.microsoft.com /en-us/library/bb510625.aspx): * L'istruzione MERGE può avere al massimo due clausole WHEN MATCHED. * ** e ** * Se ci sono due clausole WHEN MATCHED, è necessario specificare un'azione UPDATE e si deve specificare un'azione DELETE.* –

+0

@AaronBertrand, Non era la mia scelta di utilizzare MERGE, immagino usando un caso o istruzioni IF sarebbe stata la scelta migliore ... Nizza articolo a proposito – Chris

risposta

5

Nella tua MERGE dichiarazione, si dispone di tre WHEN MATCHED clausole

  • Due con un UPDATE dichiarazione
  • Uno con un INSERT dichiarazione.

Tuttavia, ciò non è consentito. E 'chiaramente indicato nel Documentation on MERGE:

La dichiarazione MERGE può avere al massimo due WHEN MATCHED clausole.

E

Se ci sono due WHEN MATCHED clausole, allora si deve specificare UPDATE azione e si deve specificare un'azione DELETE.

anche importante sapere è:

Se UPDATE è specificato nel <merge_matched> clausola, e più di una fila di <table_source> partite di fila in target_table sulla base di <merge_search_condition>, SQL Il server restituisce un errore. L'istruzione MERGE non può aggiornare la stessa riga più di una volta, oppure aggiornare ed eliminare la stessa riga.