I have a client c# program that is executing stored procedures via ExectueNonQuery
, including catching the PRINT
and Error output with InfoMessage events. It works fine, but I have noticed something odd.
When I execute a stored procedure from SSMS, it displays rowcounts for each individual SQL statement that is executed in the Messages tab (as though it were coming from the InfoMessages). However my program never sees these messages, though it does catch all of the same other output. Instead, it just returns the rows affected in the ExecuteNonQuery function result that is the sum of all of the individual rowcounts (which is kind of useless).
For example, this procedure:
use [tempdb]
go
SELECT *
INTO MyCols
FROM sys.columns
go
CREATE PROC foo As
UPDATE MyCols
SET name = name + N''
-- SSMS shows (662 row(s) affected)
UPDATE MyCols
SET name = name + N''
WHERE name like '%x%'
-- SSMS shows (59 row(s) affected)
PRINT 'bar'
-- both SSMS and ExecuteNonQuery get this
-- ExecuteNonQuery returns 721 rows affected
GO
When the foo
proc is run, SSMS displays rowcounts of 662 and 59, but ExecuteNonQuery
only returns the total of 721.
So, how can I get the same information that SSMS is getting?
Just to be clear here: I am not interested in how to change the stored procedures to add PRINT @@ROWCOUNT
s after every SQL statement. I know how to do that and it's not an option most of the time for a variety of reasons.
I am asking how to do what SSMS is doing here. I can change the client code all I want at this point (for right now, anyway) and I would like to do it right.
Best Answer
The
SqlCommand.StatementCompleted
event will fire after each statement in a batch, and one of the properties of the event (well, pretty much the only property) is the number of rows affected by the statement that fired the event.Some notes:
SET NOCOUNT ON;
, or conversely, you did specifySET NOCOUNT OFF;
.Execute___()
, not during the execution.StatementCompletedEventArgs.RecordCount
includes row counts fromSELECT
statements, whereas the SqlDataReader.RecordsAffected property only reports row counts from DML statements (INSERT
,UPDATE
,DELETE
, etc).StatementCompleted
event does not include the individual SQL statement from the batch that fired the event. However, the event handler is sent thesender
as an input parameter and this is theSqlCommand
of the query batch, and you can see that batch by castingsender
toSqlCommand
and then looking at theCommandText
property (this is shown in the example below).The documentation is very sparse on this so I have worked up an example that shows this event firing for both
ExecuteNonQuery
andExecuteScalar
, as well as for both ad hoc queries and stored procedures (i.e.SqlCommand.CommandType
ofText
vsStoredProcedure
):OUTPUT: