views:

475

answers:

2

I'm wondering what y'alls would recommend as the best way to go about getting the action counts from a MERGE statement in Sql Server.

So, i.e. I run a MERGE which does some inserts, some updates and some deletes, ... I would like to be able to find out HOW MANY inserts, HOW MANY updates and How Many deletes.

What'd be the best way to do this?

+1  A: 

You could specify an OUTPUT clause on your MERGE statement and get an output report of what's been done during MERGE.

MERGE (targetTable) AS t 
USING (sourceTable) AS s
ON t.ID = s.ID
WHEN MATCHED THEN
  (some statements)
WHEN NOT MATCHED THEN
  (some statements)
OUTPUT
  $action, inserted.ID 'inserted', deleted.ID 'deleted'
;

This will give you a row for each "action" (insert, update, delete) for each operation. If it's a lot of statements, you could also OUTPUT INTO @tableVar and then look at the table variable.

DECLARE @tableVar TABLE (MergeAction VARCHAR(20), InsertedID INT, DeletedID INT)

MERGE (targetTable) AS t 
USING (sourceTable) AS s
ON t.ID = s.ID
WHEN MATCHED THEN
      (some statements)
WHEN NOT MATCHED THEN
      (some statements)
OUTPUT
      $action, inserted.ID 'inserted', deleted.ID 'deleted' INTO @tableVar
;

SELECT MergeAction, COUNT(*) 
FROM @tableVar  
GROUP BY MergeAction

Check out the Books Online for details on the MERGE statement and the OUTPUT clause.

Marc

marc_s
Is it possible somehow to do this in one statement, possibly with a group by? so that the output bit would be something sort of along the lines of > OUTPUT $ACTION, COUNT(1) GROUP BY $ACTION ?
eidylon
No, you cannot do this. You can either just OUTPUT to the SSMS output window, or into a table variable - don't over-stretch the OUTPUT clause!! :-)
marc_s
Ah well... Actually, does OUTPUT put out a table variable, or a resultset? Would it be possible to wrap the MERGE statement with an OUTPUT clause inside a SELECT statement as the source (as a subquery) and then have that outer SELECT do the aggregation? ... Sounds possible. I may have to play with that.
eidylon
OUTPUT can send its output directly to your result grid in SSMS, or into a table variable - that's it, according to the MSDN library. You cannot do any of the trickery you want to do - you'll have to use the steps as I showed them - sorry, you're trying to do something that SQL Server does not support
marc_s
You cannot seem to use the MERGE statement in either a SELECT * FROM (MERGE as a subselect) or a Common Table Expression (WITH MergeOutput AS (MERGE:......)SELECT MergeAction.....) - it just doesn't work that way. You can output your values into the output window, a table variable, or a new table (on disk) - but you cannot use it directly as an output result set.
marc_s
I messed around, with this solution and got it working for my needs. Thanks!
eidylon
A: 

How about:

INSERT YourResultsTable (action, cnt)
SELECT action, count(*)
FROM
(
    MERGE (targetTable) AS t 
    USING (sourceTable) AS s
       ON t.ID = s.ID
    WHEN MATCHED THEN      (some statements)
    WHEN NOT MATCHED THEN      (some statements)
    OUTPUT $action as action, inserted.ID as ins, deleted.ID as del
) m
GROUP BY action;

[Edit] Ok, so try:

INSERT YourResultsTable (action)
SELECT action
FROM
(
    MERGE (targetTable) AS t 
    USING (sourceTable) AS s
       ON t.ID = s.ID
    WHEN MATCHED THEN      (some statements)
    WHEN NOT MATCHED THEN      (some statements)
    OUTPUT $action as action, inserted.ID as ins, deleted.ID as del
) m;

(and then count the results)

Rob

Rob Farley
Nope: Msg 10717, Level 15, State 1, Line 48The GROUP BY clause is not allowed when the FROM clause contains a nested INSERT, UPDATE, DELETE, or MERGE statement.
marc_s
Tested on SQL Server 2008 Developer Edition
marc_s