[c#] C #에서 SqlDataReader를 사용하여 행 수를 얻는 방법

내 질문은 SqlDataReaderC #에서 사용하는 쿼리 에서 반환되는 행 수를 얻는 방법 입니다. 나는 이것에 대한 몇 가지 답변을 보았지만 Read()메서드 로 while 루프를 수행 하고 카운터를 증가시키는 것을 제외하고는 명확하게 정의되지 않았습니다 .

내 문제는 첫 번째 행이 열 머리글 이름이고 그 이후의 모든 행이 행 데이터가되도록 다차원 배열을 채우려 고한다는 것입니다.

나는 List 컨트롤에 물건을 버리고 그것에 대해 걱정할 필요가 없다는 것을 알고 있지만, 개인적인 수정을 위해 데이터를 선택하고 다른 형식으로 표시 할 때 배열 안팎으로 가져오고 싶습니다.

그래서 나는 할 수 없다고 생각 Read()하고 ++ 방식으로 증가 시킬 수 없다고 생각합니다. 왜냐하면 그것은 행의 양과 열 데이터를 얻기 위해 Read()열었다가 Read()다시 열어야 함을 의미하기 때문입니다 .

내가 말하는 것에 대한 작은 예 :

int counter = 0;    

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

그런 다음 for 루프가 열을 통과하고 팝합니다.

something.Read();

int dbFields = sqlRead.FieldCount;

for (int i = 0; i < dbFields; i++)
{
   // do stuff to array
}



답변

두 가지 옵션 만 있습니다.

  • 모든 행을 읽고 알아 내십시오 (그런 다음 저장하는 것이 좋습니다).

  • 사전에 특수 SELECT COUNT (*) 쿼리를 실행하십시오.

DataReader 루프를 두 번 통과하는 것은 비용이 많이 들기 때문에 쿼리를 다시 실행해야합니다.

그리고 (Pete OHanlon 덕분에) 두 번째 옵션은 스냅 샷 격리 수준의 트랜잭션을 사용할 때만 동시성에 안전합니다.

어쨌든 메모리에 모든 행을 저장하고 싶기 때문에 유일한 현명한 옵션은 유연한 저장소 ( List<>또는 DataTable)의 모든 행을 읽은 다음 원하는 형식으로 데이터를 복사하는 것입니다. 메모리 내 작업은 항상 훨씬 더 효율적입니다.


답변

모든 행을 검색 할 필요가없고 이중 쿼리를 작성하지 않으려면 다음과 같이 시도 할 수 있습니다.

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();
      }

동일한 명령을 재사용하면 자동으로 트랜잭션이 추가되는지 확실하지 않은 트랜잭션을 추가해야 할 수 있습니다.


답변

위의 내용에 따라 데이터 세트 또는 유형이 지정된 데이터 세트는 필터링에 사용할 수있는 좋은 테머 러리 구조 일 수 있습니다. SqlDataReader는 데이터를 매우 빠르게 읽는 것을 의미합니다. while () 루프에있는 동안 여전히 DB에 연결되어 있으며 계속 진행하기 전에 다음 결과를 읽고 / 처리하기 위해 수행중인 작업을 기다리고 있습니다. 이 경우 모든 데이터를 가져 와서 DB에 대한 연결을 닫고 결과를 “오프라인”으로 처리하면 더 나은 성능을 얻을 수 있습니다.

사람들은 데이터 세트를 싫어하는 것 같으므로 위의 작업은 강력한 형식의 개체 모음으로도 수행 할 수 있습니다.


답변

Firehose 커서로 알려진 것이기 때문에 데이터 판독기에서 직접 행 수를 가져올 수 없습니다. 즉, 수행중인 읽기에 따라 행 단위로 데이터를 읽습니다. 두 번의 읽기를 수행하는 사이에 데이터가 변경되어 다른 결과를 얻을 수 있기 때문에 데이터에 대해 두 번의 읽기를 수행하지 않는 것이 좋습니다.

할 수있는 일은 데이터를 임시 구조로 읽어서 두 번째 읽기 대신 사용하는 것입니다. 또는 데이터를 검색하고 대신 DataTable과 같은 것을 사용하는 메커니즘을 변경해야합니다.


답변

Pit 답변을 완료하고 더 나은 성능을 얻으려면 : 하나의 쿼리에서 모두 가져오고 NextResult 메서드를 사용하십시오.

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;select @@ROWCOUNT;";
    using (var reader = com.ExecuteReader())
    {
        while(reader.read()){
            //iterate code
        }
        int totalRow = 0 ;
        reader.NextResult(); // 
        if(reader.read()){
            totalRow = (int)reader[0];
        }
    }
    sqlCon.Close();
}


답변

또한 상위 결과를 반환해야하는 상황에 직면했지만 쿼리와 일치하는 총 행을 가져오고 싶었습니다. 마지막 으로이 솔루션에 도달합니다.

   public string Format(SelectQuery selectQuery)
    {
      string result;

      if (string.IsNullOrWhiteSpace(selectQuery.WherePart))
      {
        result = string.Format(
@"
declare @maxResult  int;
set @maxResult = {0};

WITH Total AS
(
SELECT count(*) as [Count] FROM {2}
)
SELECT top (@maxResult) Total.[Count], {1} FROM Total, {2}", m_limit.To, selectQuery.SelectPart, selectQuery.FromPart);
      }
      else
      {
        result = string.Format(
@"
declare @maxResult  int;
set @maxResult = {0};

WITH Total AS
(
SELECT count(*) as [Count] FROM {2} WHERE {3}
)
SELECT top (@maxResult) Total.[Count], {1} FROM Total, {2} WHERE {3}", m_limit.To, selectQuery.SelectPart, selectQuery.FromPart, selectQuery.WherePart);
      }

      if (!string.IsNullOrWhiteSpace(selectQuery.OrderPart))
        result = string.Format("{0} ORDER BY {1}", result, selectQuery.OrderPart);

      return result;
    }


답변