从多个语句中检索记录数

Retrieve record counts from multiple statements

我写了自己的 SQL 客户端,因为我厌倦了 SSMS。我想像 SSMS 一样捕获受影响的行数,但是 SqlCommand.StatementCompleted ExecuteReader 完成(或调用 EndExecuteReader 时多次引发)。尽管批处理中的语句以固定间隔完成,但似乎 DONE_IN_PROC 消息在客户端排队,然后一次性全部转储,而不是连续引发。InfoMessage 事件从 SqlConnection 开始执行。

更新 上面 斜体.

比如说,你有一个 SQL 循环更新行的语句,或者类似的语句:

WHILE 1=1 
BEGIN 
  UPDATE tbl SET .... WHERE Id BETWEEN i AND i+10; 
  IF @@ROWCOUNT =0 BREAK; 
  SET i = i + 10; 
END

SSMS 每 X 秒或 w/e 正确显示“(受影响的 10 行)”。 没有来自 reader 的记录,因为这是一个 UPDATE only 语句,所以不能使用 SqlDataReader 来计算行数。

这可能吗,使用 SqlClient 库?

有问题的简化代码是这样的:

class ExecuteWorker
{
  public void Start(string query)
  {
    this._query = query;
    this._thread.Start(this.Work);
  }

  void Work()
  {
    using(var conn = new SqlConnection(this._connStr))
    {
      conn.Open();
      using(var command = conn.CreateCommand())
      {
        command.CommandText = this._query;
        using(var reader = command.ExecuteReader())
        {
          while(reader.Read())
          {
            this._control.BeginInvoke(new Action(()=>{
              // update UI
            }));
          }
        }
      }
    }
  }
}

发现了类似的问题 here,但描述不太清楚。

为什么不将 sql 移动到存储过程中。 使用带有参数集合(包括输出参数)的命令对象执行存储过程。在存储过程中有一个总计数变量来计算受影响的每个单独更新行的总和。 Return 这是一个输出参数。

当您使用 ExecuteNonQuery 方法更新数据库时,它会影响 returns 行数。当您使用插入、更新或删除 sql 命令时使用此方法。希望这就是您要找的。

您要处理两个事件。 SqlConnection InfoMessageSqlCommand StatementCompleted.

抱歉 VB 代码,但您应该可以转换它。

Private Sub OnInfoMessage(sender As Object, args As SqlClient.SqlInfoMessageEventArgs)
    For Each sqlEvent As System.Data.SqlClient.SqlError In args.Errors
        Dim msg As String = String.Format("Msg {0}, Level {1}, State {2}, Line {3}{4}", sqlEvent.Number, sqlEvent.Class, sqlEvent.State, sqlEvent.LineNumber, Environment.NewLine)
        'Write msg to output
    Next
End Sub

Private Sub OnStatementCompleted(sender As Object, args As StatementCompletedEventArgs)
    Dim msg As String = String.Format("({0} row(s) affected)", args.RecordCount)
    'Write msg to output
End Sub

Public Sub Work()
    Using dbc As New SqlConnection(Me.ConnectionString),
          dbcmd As New SqlCommand()

        dbcmd.Connection = dbc
        dbcmd.CommandTimeout = Convert.ToInt32(timeout) ' you will want to set this otherwise it will timeout after 30 seconds
        'set other dbcmd properties

        AddHandler dbc.InfoMessage, New SqlInfoMessageEventHandler(AddressOf OnInfoMessage)
        AddHandler dbcmd.StatementCompleted, AddressOf OnStatementCompleted

        dbc.Open()

        'dbcmd.ExecuteNonQuery() or Using dataReader As SqlDataReader = dbcmd.ExecuteReader()

    End Using
End Sub