从SqlDataReader获取结果集的数量

时间:2013-08-08 09:53:00

标签: c# sql sql-server sqldatareader

我有一个SQL Server存储过程,它返回多个结果。存储过程的主体可能如下所示:

SELECT * FROM tableA;
SELECT * FROM tableB;
SELECT * FROM tableC;

在这种情况下,存储过程返回3个结果集。其他存储过程可能返回例如1,0或任何数量的结果集。每个结果集中可能包含0行或更多行。加载这些内容时,我需要调用IDataReader.NextResult()来在结果集之间导航。

如何在C#中可靠地获取结果集(不是行数)?

2 个答案:

答案 0 :(得分:7)

似乎没有直接计算IDataReader中结果计数的属性或方法。该接口更倾向于以增量/流式方式使用。因此,要计算返回的结果集数量,请在每次调用IDataReader.NextResult()时递增计数器,并在消耗数据时返回true

然而,有一个问题。该 IDataReader.NextResult()州的文档:

  

默认情况下,数据读取器位于第一个结果上。

请考虑以下情况:

  • 该命令返回0个结果集。您第一次致电IDataReader.NextResult()会返回false
  • 该命令返回1个结果集。您第一次致电IDataReader.NextResult()会返回false
  • 该命令返回了2个结果集。您对IDataReader.NextResult()的第二次通话会返回false

只要至少有一个结果集,您就可以看到我们有足够的信息来计算结果集的数量。这将是IDataReader.NextResult()返回true加一。

的次数

要检测是否有0个结果集,我们使用读者的另一个属性:IDataRecord.FieldCount。该属性的文档声明:

  

当未定位在有效记录集中时,0;否则,当前记录中的列数。默认值为-1。

因此,我们可以在首次打开阅读器时读取该字段,以确定我们是否在有效的结果集中。如果该命令不生成结果集,则阅读器上的IDataRecord.FieldCount值最初将小于1.如果该命令至少生成一个结果集,则该值最初为正数。这假设结果集不可能有0列(我认为你可以用SQL假设,不确定)。

所以,我会使用类似下面的内容来计算结果集的数量。如果您还需要保存数据,则必须将该逻辑插入到此:

using (var reader = command.ExecuteReader())
{
    var resultCount = 0;
    do
    {
        if (reader.FieldCount > 0)
            resultCount++;

        while (reader.Read())
        {
            // Insert logic to actually consume data here…
            // HandleRecordByResultIndex(resultCount - 1, (IDataRecord)reader);
        }
    } while (reader.NextResult());
}

我已使用System.Data.SqlClient和命令PRINT 'hi'(0结果集),SELECT 1 x WHERE 1=0(1个结果集)和SELECT 1 x WHERE 1=0; SELECT 1 x WHERE 1=0(2个结果集)对此进行了测试

答案 1 :(得分:6)

使用DataReader.NextResult将读者推进到下一个结果集。:

using (var con = new SqlConnection(Properties.Settings.Default.ConnectionString))
{
    using (var cmd = new SqlCommand("SELECT * FROM TableA; SELECT * FROM TableB; SELECT * FROM TableC;", con))
    {
        con.Open();
        using (IDataReader rdr = cmd.ExecuteReader())
        {
            while (rdr.Read())
            {
                int firstIntCol = rdr.GetInt32(0); // assuming the first column is of type Int32
                // other fields ...
            }
            if (rdr.NextResult())
            {
                while (rdr.Read())
                {
                    int firstIntCol = rdr.GetInt32(0); // assuming the first column is of type Int32
                    // other fields ...
                }
                if (rdr.NextResult())
                {
                    while (rdr.Read())
                    {
                        int firstIntCol = rdr.GetInt32(0); // assuming the first column is of type Int32
                        // other fields ...
                    }
                }
            }
        }
    }
}