Làm cách nào tôi có thể nhận được số lượng cá nhân như SSMS?


8

Tôi có một chương trình c # máy khách đang thực hiện các thủ tục được lưu trữ thông qua ExectueNonQuery, bao gồm cả việc bắt PRINTđầu ra và Lỗi với các sự kiện InfoMessage. Nó hoạt động tốt, nhưng tôi đã nhận thấy một cái gì đó kỳ lạ.

Khi tôi thực hiện một thủ tục được lưu trữ từ SSMS, nó sẽ hiển thị số lượng hàng cho từng câu lệnh SQL riêng lẻ được thực thi trong tab Tin nhắn (như thể nó đến từ InfoMessages). Tuy nhiên, chương trình của tôi không bao giờ nhìn thấy những thông báo này, mặc dù nó không bắt được tất cả các đầu ra khác. Thay vào đó, nó chỉ trả về các hàng bị ảnh hưởng trong kết quả hàm ExecuteNonQuery là tổng của tất cả các hàng riêng lẻ (loại này là vô dụng).

Ví dụ: quy trình này:

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

Khi fooProc được chạy, SSMS hiển thị số lượng hàng là 662 và 59, nhưng ExecuteNonQuerychỉ trả về tổng số 721.

Vậy, làm thế nào tôi có thể có được thông tin tương tự mà SSMS đang nhận được?


Chỉ cần rõ ràng ở đây: Tôi không quan tâm đến cách thay đổi các thủ tục được lưu trữ để thêm PRINT @@ROWCOUNTs sau mỗi câu lệnh SQL. Tôi biết làm thế nào để làm điều đó và nó không phải là một lựa chọn hầu hết thời gian vì nhiều lý do.

Tôi đang hỏi làm thế nào để làm những gì SSMS đang làm ở đây. Tôi có thể thay đổi mã máy khách tất cả những gì tôi muốn tại thời điểm này (ngay bây giờ, dù sao đi nữa) và tôi muốn làm điều đó ngay.

Câu trả lời:


6

Sự SqlCommand.StatementCompletedkiện sẽ kích hoạt sau mỗi câu lệnh trong một đợt và một trong các thuộc tính của sự kiện (tốt, khá nhiều thuộc tính duy nhất) là số hàng bị ảnh hưởng bởi câu lệnh đã kích hoạt sự kiện.

Một số lưu ý:

  • Yêu cầu nhận thông tin này là bạn không chỉ định SET NOCOUNT ON;hoặc ngược lại, bạn đã chỉ định SET NOCOUNT OFF;.
  • Tất cả các sự kiện diễn ra khi hoàn thành mỗi sự kiện Execute___(), không phải trong khi thực hiện.
  • Các StatementCompletedEventArgs.RecordCountbao gồm đếm hàng từ SELECTbáo cáo, trong khi SqlDataReader.RecordsAffected tài sản duy nhất báo cáo số lượng hàng từ các báo cáo DML ( INSERT, UPDATE, DELETE, vv).
  • Sự StatementCompletedkiện này không bao gồm câu lệnh SQL riêng lẻ từ lô phát sinh sự kiện. Tuy nhiên, trình xử lý sự kiện được gửi senderdưới dạng tham số đầu vào và đây là SqlCommandlô truy vấn và bạn có thể thấy lô đó bằng cách truyền sendertới SqlCommandvà sau đó xem thuộc CommandTexttính (điều này được hiển thị trong ví dụ bên dưới).

Các tài liệu là rất thưa thớt về vấn đề này vì vậy tôi đã làm việc lập một ví dụ cho thấy sự kiện này bắn cho cả hai ExecuteNonQueryExecuteScalarcũng như cho cả quảng cáo hoc truy vấn và lưu trữ thủ tục (tức là SqlCommand.CommandTypecủa Textvs 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();
        }
    }
}

ĐẦU RA:

Truy vấn hàng loạt:
TẮT NOCOUNT; - đảm bảo rằng sự kiện 'StatementCompleted' được kích hoạt

EXEC ('TẠO QUY TRÌNH #TestProc NHƯ CHỌN * TỪ sys.objects;

CHỌN * TỪ sys.tables; ');

CHỌN * TỪ sys.objects;

Hàng bị ảnh hưởng: 453

Truy vấn hàng loạt:
CHỌN 123 AS [Bob];

CHẬM TRÌ HOÃN '00: 00: 05.000 '; - 5 giây tạm dừng

CHỌN 2 NHƯ [Sally] UNION ALL CHỌN 5;

Hàng bị ảnh hưởng: 1

Truy vấn hàng loạt:
CHỌN 123 AS [Bob];

CHẬM TRÌ HOÃN '00: 00: 05.000 '; - 5 giây tạm dừng

CHỌN 2 NHƯ [Sally] UNION ALL CHỌN 5;

Hàng bị ảnh hưởng: 2

123

Hàng loạt truy vấn: #TestProc
Row (s) bị ảnh hưởng: 453

Truy vấn hàng loạt: #TestProc
Row (s) bị ảnh hưởng: 17


1
Tôi đã thử điều này và nó làm việc cho tôi. Điều kỳ lạ là StatementCompletions và InfoMessages từ các câu lệnh PRINT trong các thủ tục được lưu trữ dường như không được đồng bộ hóa với nhau (Tôi nhận được một loạt StatementCompletions, sau đó là một loạt các kết quả câu lệnh PRINT, mặc dù chúng được cho là xen kẽ) Nhưng tôi đoán đó là một trò lừa SSMS cho một ngày khác ...
RBarryYoung

1
@RBarryYoung Vâng, hành vi đó, tôi tin là sẽ được mong đợi, ngay cả khi gây phiền nhiễu. Nó phải thực hiện theo thứ tự của các mục trong TDS (Luồng dữ liệu dạng bảng): msdn.microsoft.com/en-us/l Library / dd304523.aspx . Tôi biết rằng tất cả các tin nhắn PRINTRAISERROR(..., 10, 1)sau khi kết quả được thiết lập. Tôi đang cố gắng tìm thông điệp đặt hàng trong tài liệu đó nhưng cho đến nay vẫn chưa bắt gặp.
Solomon Rutzky

Điều bí ẩn đối với tôi là làm thế nào SSMS sắp xếp nó một cách chính xác.
RBarryYoung

1
@RBarryYoung Có lẽ đây là một câu hỏi riêng vì câu hỏi này chỉ là về số lượng hàng từ các truy vấn riêng lẻ? Đó là một câu hỏi hay, và tôi đã tìm ra nó :). Tôi sẽ đăng nó dưới dạng câu hỏi nếu tôi có cơ hội làm điều đó trước khi bạn nhận được nó.
Solomon Rutzky

1
@RBarryYoung Yike. Xin lỗi để nghe về điều đó. Hy vọng bạn đang trên mend. Tôi sẽ cố gắng để có được nó trong vòng vài ngày tới. Tôi chỉ còn một hoặc hai biến thể để kiểm tra mà tôi nghĩ đến sau khi tôi đăng tin nhắn cuối cùng đó. Tôi sẽ đăng liên kết đến đây.
Solomon Rutzky

-1

Kết quả thực thi không thực hiện được những gì bạn muốn ở đây. Nhưng bạn vẫn có thể đến đó, nó chỉ phụ thuộc vào những gì bạn muốn sử dụng thông tin cho.

Bạn có thể thêm dòng này sau mỗi lần chèn "PRINT @@ ROWCOUNT" và bạn sẽ nhận được số lượng hàng bị ảnh hưởng bởi thao tác trước đó như một phần của đầu ra (nơi bạn nhận được "thanh".

Ngoài ra, bạn có thể thêm một tham số "OUTPUT" vào quy trình được lưu trữ của mình để giữ kết quả và sau đó chỉ cần nắm bắt điều đó khi bạn chạy tệp thực thi.

BIÊN TẬP:

Tôi đã xoay sở để sửa đổi mẫu mà Jonathan Kehasias ghép lại để đưa vào xử lý sự kiện được hoàn thành. Chỉ cần thêm hai dòng này.

#Add handler for StatementCompleted
$statementhandler = {param($sender, [System.Data.StatementCompletedEventArgs]$event) Write-Host $event.RecordCount };

#Attach handler...
$cmd.add_StatementCompleted($statementhandler)

Tôi không thể sửa đổi các thủ tục này. Tôi có thể sửa đổi mã máy khách, bao gồm cả việc sử dụng thứ gì đó ngoài ExecuteNonQuery.
RBarryYoung

Bạn có thể thử gắn một trình xử lý sự kiện vào sự kiện thông tin sqlcommand. Bài viết này cho thấy làm thế nào để làm điều đó bằng cách sử dụng powershell. sqlskills.com/bloss/jonathan/ Kẻ
Jonathan Fite

Nếu bạn đã đọc câu hỏi của tôi, bạn sẽ thấy rằng tôi đã làm điều đó. Nó không ở trong đó.
RBarryYoung

1
Câu hỏi này trong khu vực C # nói rằng việc thêm một người nghe vào sự kiện SQLCommand.StatementCompleted đã cho họ những gì họ đang tìm kiếm. stackoverflow.com/questions/27993049/
Jonathan Fite
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.