views:

77

answers:

1

Is there a way to determine whether a record was matched or not (whether the record was inserted or updated) after calling MERGE?

Ideally I'd like to output it to a parameter.

Edit: I've got the merge statement outputting what happened in my management studio using the following statement: Say I had the following merge statement:

MERGE INTO TestTable as target
USING ( select '00D81CB4EA0842EF9E158BB8FEC48A1E' )
AS source (Guid)
ON ( target.Guid = source.Guid ) 
WHEN MATCHED THEN
UPDATE SET Test_Column = NULL
WHEN NOT MATCHED THEN
INSERT (Guid, Test_Column) VALUES ('00D81CB4EA0842EF9E158BB8FEC48A1E', NULL)
OUTPUT $action;

I'm trying to use a parameter to get the '$action' output.

+2  A: 

What you could do is create a temporary table (or a table variable) and send your output there - add some meaningful fields to your OUTPUT clause to make it clear what row was affected by what action:

DECLARE @OutputTable TABLE (Guid UNIQUEIDENTIFIER, Action VARCHAR(100))

MERGE INTO TestTable as target
USING ( select '00D81CB4EA0842EF9E158BB8FEC48A1E' )
AS source (Guid)
ON ( target.Guid = source.Guid ) 
WHEN MATCHED THEN
UPDATE SET Test_Column = NULL
WHEN NOT MATCHED THEN
INSERT (Guid, Test_Column) VALUES ('00D81CB4EA0842EF9E158BB8FEC48A1E', NULL)
OUTPUT INSERTED.Guid, $action INTO @OutputTable

SELECT
   Guid, Action
FROM
   @OutputTable

UPDATE: ah, okay, so you want to call this from .NET ! Well, in that case, just call it using the .ExecuteReader() method on your SqlCommand object - the stuff you're outputting using OUTPUT... will be returned to the .NET caller as a result set - you can loop through that:

using(SqlCommand cmd = new SqlCommand(mergeStmt, connection))
{
   connection.Open();

   using(SqlDataReader rdr = cmd.ExecuteReader())
   {
      while(rdr.Read())
      {
         var outputAction = rdr.GetValue(0);
      }

      rdr.Close();
   }
   connection.Close();
}

You should get back the resulting "$action" from that data reader.

marc_s
thanks!so there is no way to use SqlCommand.Parameters to get the $action then?
petejamd
additionally, using ExecuteScalar if you know you're only going to get one row modified is prefered
petejamd
@petejamd: actually, ExecuteScalar should be used only when you get one row *and* one column back! Just a single result that is. And no - the $action cannot be accessed through the SqlCommand.Parameters collection - it's neither an input nor an output parameter, but part of a result set.
marc_s
you are correct :)
petejamd