如何获得像 SSMS 这样的单个行计数?

RBa*_*ung 9 sql-server ado.net sql-server-2008-r2

我有一个客户端 c# 程序,它通过 执行存储过程ExectueNonQuery,包括PRINT使用 InfoMessage 事件捕获和错误输出。它工作正常,但我注意到一些奇怪的事情。

当我从 SSMS 执行存储过程时,它会显示在“消息”选项卡中执行的每个单独 SQL 语句的行数(就好像它来自 InfoMessages)。然而,我的程序从未看到这些消息,尽管它确实捕获了所有相同的其他输出。相反,它只返回 ExecuteNonQuery 函数结果中受影响的行,即所有单个行计数的总和(这是一种无用的)。

例如,这个过程:

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
Run Code Online (Sandbox Code Playgroud)

fooproc 运行时,SSMS 显示 662 和 59 的行数,但ExecuteNonQuery只返回 721 的总数。

那么,我怎样才能获得与 SSMS 获得的信息相同的信息呢?


在这里要明确:我对如何更改存储过程以PRINT @@ROWCOUNT在每个 SQL 语句之后添加s不感兴趣。我知道如何做到这一点,而且由于各种原因,大多数时候这不是一种选择。

我在问如何做 SSMS 在这里所做的事情。在这一点上,我可以随心所欲地更改客户端代码(现在,无论如何),我想做得对。

Sol*_*zky 7

SqlCommand.StatementCompleted事件将在批处理中的每个语句之后触发,并且该事件的一个属性(好吧,几乎是唯一的属性)是受触发该事件的语句影响的行数。

一些注意事项:

  • 得到这个信息的要求是,你并没有指定SET NOCOUNT ON;,或者相反,你没有指定SET NOCOUNT OFF;
  • 所有事件在 each 完成时触发Execute___(),而不是在执行期间触发。
  • StatementCompletedEventArgs.RecordCount包括从行数SELECT的语句,而SqlDataReader.RecordsAffected属性只从DML语句(报告行数INSERTUPDATEDELETE,等)。
  • StatementCompleted事件并没有包括从触发事件批次个别SQL语句。但是,事件处理程序sender作为输入参数发送,这是SqlCommand查询批次的 ,您可以通过强制转换senderSqlCommand然后查看CommandText属性来查看该批次(如下面的示例所示)。

该文档是非常稀少的这个所以我已经做了一个例子来展示这个事件引发了双方ExecuteNonQueryExecuteScalar,以及两个特设的查询和存储过程(即SqlCommand.CommandTypeTextVS StoredProcedure):

using System;
using System.Data;
using System.Data.SqlClient;

namespace StatementCompletedFiring
{
    class Program
    {
        static void Main(string[] args)
        {
            using (SqlConnection _Connection =
                          new SqlConnection("Integrated Security = True;"))
            {
                using (SqlCommand _Command = new SqlCommand(@"
SET NOCOUNT OFF; --  ensures that the 'StatementCompleted' event fires

EXEC('
CREATE PROCEDURE #TestProc
AS
SELECT * FROM sys.objects;

SELECT * FROM sys.tables;
');

SELECT * FROM sys.objects;
", _Connection))
                {

                    _Command.StatementCompleted += _Command_StatementCompleted;

                    try
                    {
                        _Connection.Open();

                        _Command.ExecuteNonQuery();

                        _Command.CommandText = @"
SELECT 123 AS [Bob];

WAITFOR DELAY '00:00:05.000'; --5 second pause to shows when the events fire

SELECT 2 AS [Sally]
UNION ALL
SELECT 5;
";
                        Console.WriteLine("\n\t");
                        Console.WriteLine(_Command.ExecuteScalar().ToString());
                        Console.WriteLine("\n");


                        _Command.CommandType = CommandType.StoredProcedure;
                        _Command.CommandText = "#TestProc";
                        _Command.ExecuteNonQuery();
                    }
                    catch (Exception _Exception)
                    {
                        throw new Exception(_Exception.Message);
                    }
                }
            }
        }

        static void _Command_StatementCompleted(object sender,
                                                StatementCompletedEventArgs e)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.Write("\nQuery Batch: ");
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine(((SqlCommand)sender).CommandText);

            Console.ForegroundColor = ConsoleColor.Red;
            Console.Write("Row(s) affected: ");
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine(e.RecordCount.ToString() + "\n");

            Console.ResetColor();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

查询批次:
SET NOCOUNT OFF; -- 确保“StatementCompleted”事件触发

EXEC(' CREATE PROCEDURE #TestProc AS SELECT * FROM sys.objects;

SELECT * FROM sys.tables; ');

SELECT * FROM sys.objects;

受影响的行数: 453

查询批次:
SELECT 123 AS [Bob];

等待延迟 '00:00:05.000'; --5 秒暂停

SELECT 2 AS [Sally] UNION ALL SELECT 5;

受影响的行: 1

查询批次:
SELECT 123 AS [Bob];

等待延迟 '00:00:05.000'; --5 秒暂停

SELECT 2 AS [Sally] UNION ALL SELECT 5;

受影响的行: 2

123

查询批次: #TestProc
受影响的行: 453

查询批次: #TestProc
受影响的行: 17