Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why WHEN MATCHED' cannot appear more than once in a 'UPDATE' clause of a MERGE statement?

I'm taking a bunch of CRUD opertations and creating merge storedprocs off the CUD. My stored proc looks like this

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;

When I go to execute this I am getting this full error

Msg 10714, Level 15, State 1, Procedure usp_AdministrationHistoryMerge, Line 36 An action of type 'WHEN MATCHED' cannot appear more than once in a 'UPDATE' clause of a MERGE statement.

I have looked around on SO and found a couple ways to resolve this, but what I have found aren't suitable solutions for this error, as instead of a delete and I need to update the record's IsActive to a 0.

Also, in my searching no one really explains why this error is being thrown, yes I know its obvious because the error is right there, but why is this not allowed to happen? and based on this circumstance are there any idea's on how to accomplish this? or should I have this merge call another storedproc when @Action is 0?

like image 519
Chris Avatar asked Jan 24 '16 15:01

Chris


People also ask

How many when matched clause can be used in a MERGE statement?

The MERGE statement can have, at most, two WHEN MATCHED clauses. If two clauses are specified, the first clause must be accompanied by an AND <search_condition> clause. For any given row, the second WHEN MATCHED clause is only applied if the first isn't.

When not matched by source does it DELETE?

We can use WHEN NOT MATCHED BY SOURCE clause in SQL Server MERGE statement to delete the rows in the target table that does not match join condition with a source table. For example, the row with locationID =2 in the target table does not match the join condition and the row is present only in the target table.

Which is faster MERGE or UPDATE?

The UPDATE statement will most likely be more efficient than a MERGE if the all you are doing is updating rows. Given the complex nature of the MERGE command's match condition, it can result in more overhead to process the source and target rows.

Can we use multiple tables in MERGE statement?

Multiple tables can be merged by columns in SQL using joins. Joins merge two tables based on the specified columns (generally, the primary key of one table and a foreign key of the other).


1 Answers

In your MERGE statement, you have three WHEN MATCHED clauses

  • Two with an UPDATE statement
  • One with an INSERT statement.

However, that is not allowed. It is clearly stated in the Documentation on MERGE:

The MERGE statement can have at most two WHEN MATCHED clauses.

And

If there are two WHEN MATCHED clauses, then one must specify an UPDATE action and one must specify a DELETE action.

Also important to know is:

If UPDATE is specified in the <merge_matched> clause, and more than one row of <table_source> matches a row in target_table based on <merge_search_condition>, SQL Server returns an error. The MERGE statement cannot update the same row more than once, or update and delete the same row.

like image 155
TT. Avatar answered Sep 22 '22 20:09

TT.