Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get number of rows using SqlDataReader in C#

My question is how to get the number of rows returned by a query using SqlDataReader in C#. I've seen some answers about this but none were clearly defined except for one that states to do a while loop with Read() method and increment a counter.

My problem is that I am trying to fill a multi-dimensional array with the first row being the column header names and every row after that to the be the row data.

I know that I can just dump the stuff in a List control and not worry about it, but for my own personal edification and I would also like to pull the data in and out of the array as I choose and display it in different formats.

So I think I can't do the Read() and then increment ++ way because that means that I would have to open Read() and then open Read() again to get amount of rows and then column data.

Just a small example of what I'm talking about:

int counter = 0;    

while (sqlRead.Read())
{
    //get rows
    counter++
}

and then a for loop to run through the columns and pop

something.Read();

int dbFields = sqlRead.FieldCount;

for (int i = 0; i < dbFields; i++)
{
   // do stuff to array
}
like image 411
Tomasz Iniewicz Avatar asked Sep 05 '09 13:09

Tomasz Iniewicz


3 Answers

There are only two options:

  • Find out by reading all rows (and then you might as well store them)

  • run a specialized SELECT COUNT(*) query beforehand.

Going twice through the DataReader loop is really expensive, you would have to re-execute the query.

And (thanks to Pete OHanlon) the second option is only concurrency-safe when you use a transaction with a Snapshot isolation level.

Since you want to end up storing all rows in memory anyway the only sensible option is to read all rows in a flexible storage (List<> or DataTable) and then copy the data to any format you want. The in-memory operation will always be much more efficient.

like image 199
Henk Holterman Avatar answered Oct 21 '22 23:10

Henk Holterman


If you do not need to retrieve all the row and want to avoid to make a double query, you can probably try something like that:

using (var sqlCon = new SqlConnection("Server=127.0.0.1;Database=MyDb;User Id=Me;Password=glop;"))
      {
        sqlCon.Open();

        var com = sqlCon.CreateCommand();
        com.CommandText = "select * from BigTable";
        using (var reader = com.ExecuteReader())
        {
            //here you retrieve what you need
        }

        com.CommandText = "select @@ROWCOUNT";
        var totalRow = com.ExecuteScalar();

        sqlCon.Close();
      }

You may have to add a transaction not sure if reusing the same command will automatically add a transaction on it...

like image 9
Pit Ming Avatar answered Oct 22 '22 01:10

Pit Ming


Per above, a dataset or typed dataset might be a good temorary structure which you could use to do your filtering. A SqlDataReader is meant to read the data very quickly. While you are in the while() loop you are still connected to the DB and it is waiting for you to do whatever you are doing in order to read/process the next result before it moves on. In this case you might get better performance if you pull in all of the data, close the connection to the DB and process the results "offline".

People seem to hate datasets, so the above could be done wiht a collection of strongly typed objects as well.

like image 8
Daniel Segan Avatar answered Oct 22 '22 00:10

Daniel Segan