Home > Blockchain >  Substitute for multiple "When Matched" with Update clause when using Merge in SQL Server
Substitute for multiple "When Matched" with Update clause when using Merge in SQL Server

Time:06-08

I have this Merge statement

MERGE Destination d
USING @Source s
    ON d.DestinationId = s.DestinationId

WHEN MATCHED AND (
    ISNULL(d.DestinationFieldOne,0) != ISNULL(s.DestinationFieldOne,0) OR
    ISNULL(d.DestinationFieldTwo,'') != ISNULL(s.DestinationFieldTwo,'') OR
    ISNULL(d.DestinationFieldThree,'') != ISNULL(s.DestinationFieldThree,'') OR
    ISNULL(d.DestinationFieldFour,'') != ISNULL(s.DestinationFieldFour,'')

THEN UPDATE SET
    d.DestinationFieldOne = s.DestinationFieldOne,
    d.DestinationFieldTwo = s.DestinationFieldTwo,
    d.DestinationFieldThree = s.DestinationFieldThree,
    d.DestinationFieldFour = s.DestinationFieldFour
WHEN MATCHED AND (
    @Deleted = 1
)
THEN UPDATE SET
    d.Deleted = 1
WHEN NOT MATCHED BY TARGET
    THEN INSERT (DestinationFieldOne, DestinationFieldTwo, DestinationFieldThree, DestinationFieldFour) VALUES (s.DestinationFieldOne, s.DestinationFieldTwo, s.DestinationFieldThree, s.DestinationFieldFour)

It's giving me

An action of type 'WHEN MATCHED' cannot appear more than once in a 'UPDATE' clause of a MERGE statement.

Is there any other way to do it?

CodePudding user response:

If either @Deleted or the other long condition, update all 5 columns:

UPDATE d set
     DestinationFieldOne    = case DestinationUpdateFlag when 1 then s.DestinationFieldOne      else d.DestinationFieldOne      end         
    ,DestinationFieldTwo    = case DestinationUpdateFlag when 1 then s.DestinationFieldTwo      else d.DestinationFieldTwo      end     
    ,DestinationFieldThree  = case DestinationUpdateFlag when 1 then s.DestinationFieldThree    else d.DestinationFieldThree    end
    ,DestinationFieldFour   = case DestinationUpdateFlag when 1 then s.DestinationFieldFour     else d.DestinationFieldFour     end
    ,Deleted                = case @Deleted when 1 then 1 else d.Deleted end
from 
    Destination d
    INNER JOIN @Source s ON d.DestinationId = s.DestinationId
    cross apply
    (select case when 
        ISNULL(d.DestinationFieldOne,0) != ISNULL(s.DestinationFieldOne,0) OR
        ISNULL(d.DestinationFieldTwo,'') != ISNULL(s.DestinationFieldTwo,'') OR
        ISNULL(d.DestinationFieldThree,'') != ISNULL(s.DestinationFieldThree,'') OR
        ISNULL(d.DestinationFieldFour,'') != ISNULL(s.DestinationFieldFour,'')
    then 1 else 0 end as DestinationUpdateFlag
    ) as q1
where @Deleted = 1 or DestinationUpdateFlag=1

CodePudding user response:

This is functionally the same as what you've written.

Which is: if @delete=1, only update the deleted column otherwise update all attributes

UPDATE Destination
SET 
    -- leave as old values if Deleted=1
    d.DestinationFieldOne =
        IIF(s.Deleted=1,d.DestinationFieldOne,s.DestinationFieldOne),
    d.DestinationFieldTwo = 
        IIF(s.Deleted=1,d.DestinationFieldTwo,s.DestinationFieldTwo),
    d.DestinationFieldThree = 
        IIF(s.Deleted=1,d.DestinationFieldThree,s.DestinationFieldThree),
    d.Deleted = IIF(s.Deleted=1,1,d.Deleted)
FROM Destination d
INNER JOIN @Source s
ON d.DestinationId = s.DestinationId

But, if i make some bold assumptions about what's in @Source, I suspect this is fine:

UPDATE Destination
SET 
    d.DestinationFieldOne = s.DestinationFieldOne,
    d.DestinationFieldTwo = s.DestinationFieldTwo,
    d.DestinationFieldThree = s.DestinationFieldThree,
    d.Deleted = s.Deleted
FROM Destination d
INNER JOIN @Source s
ON d.DestinationId = s.DestinationId
  • Related