Rob Levine
Rob Levine

Reputation: 41298

Sql Server 2008 MERGE like operation, but acting on different tables

I've been using the MERGE operation in SQL Server 2008, but have now come across a similar scenario where I need the same "detection" behaviour (WHEN MATCHED, WHEN NOT MATCHED BY SOURCE, WHEN NOT MATCHED BY TARGET), but want the resulting operations to be on different tables, not the source or the target.

In other words, I have two result-sets, beforeTable and afterTable and I want to do something along the lines of:

MERGE afterTable AS dest
USING beforeTable AS source 
ON (dest.ID = source.ID)
WHEN MATCHED THEN 
    --INSERT tblModifiedItems (ID) VALUES (ID)
WHEN NOT MATCHED BY TARGET THEN
    --INSERT tblRemovedItems (ID) VALUES (ID)
WHEN NOT MATCHED BY SOURCE THEN
    --INSERT tblAddedItems (ID) VALUES (ID)

Presently I do this with three seperate (albeit very simple) queries across the two tables, but the MERGE approach would allow it to be done as a single operation. I just can't see whether it can be used to target different tables than the two under comparison.

Is this possible, and if so how?

[EDIT]

The reason I want to do this is not due to issues around atomicity of the INSERTS into added/removed/modifed (the whole thing is already in a transaction). It is because I want to be able to generate the three sets of data in a single query, or at least a single statement which also makes the intent very clear.

Upvotes: 1

Views: 777

Answers (1)

Diego
Diego

Reputation: 36146

short answer would be: no, you can't. MERGE is an operation between source table and destination table and that's it. But, I suggest an work-around (there is always one). You'll have to write some more code, but it will do the trick.

Do this:

DECLARE @AuxTable table(    
    id int,
    OLD_name varchar(50),
    new_name varchar(50)
    )

merge table2 as dest
using table1 as src
on (dest.id=src.id)
when not matched by target then
  insert (id, name) values (src.id, src.name)
when matched then
  UPDATE SET dest.NAME=src.name
when not matched by SOURCE then
   DELETE

  output inserted.id, DELETED.name, INSERTED.NAME
  into @AuxTable
  ;

  select * from @AuxTable

see the "output into @AuxTable"? That will insert all the modified values by your merge on a temp table. What yo'll have to do is run through this table and build a string to execute the SQL on your other table.

Use this logic:

  • WHEN OLD_NAME = NULL -> INSERT
  • WHEN OLD_NAME != NEW_NAME -> UPDATE
  • WHEN NEW_NAME = NULL -> DELETE

Upvotes: 2

Related Questions