C # में SqlDataReader का उपयोग करके पंक्तियों की संख्या कैसे प्राप्त करें


98

मेरा प्रश्न है कि SqlDataReaderC # का उपयोग करके किसी क्वेरी द्वारा वापस लौटी पंक्तियों की संख्या कैसे प्राप्त की जाए । मैंने इस बारे में कुछ उत्तर देखे हैं, लेकिन किसी को भी स्पष्ट रूप से परिभाषित नहीं किया गया है, सिवाय इसके कि एक Read()विधि और वेतन वृद्धि के साथ कुछ समय के लिए किया जाए।

मेरी समस्या यह है कि मैं पहली पंक्ति वाले कॉलम हेडर नाम और उसके बाद प्रत्येक पंक्ति को पंक्ति डेटा होने के लिए एक बहुआयामी सरणी भरने की कोशिश कर रहा हूं।

मुझे पता है कि मैं सिर्फ एक सूची नियंत्रण में सामान को डंप कर सकता हूं और इसके बारे में चिंता नहीं कर सकता, लेकिन अपने स्वयं के व्यक्तिगत संपादन के लिए और मैं डेटा को सरणी में और बाहर खींचना चाहूंगा, जैसा कि मैं चुनता हूं और इसे विभिन्न प्रारूपों में प्रदर्शित करता हूं।

इसलिए मुझे लगता है कि मैं ऐसा नहीं कर सकता Read()और फिर वेतन वृद्धि ++ तरीका है क्योंकि इसका मतलब है कि मुझे खोलना होगा Read()और फिर Read()पंक्तियों की मात्रा और फिर स्तंभ डेटा प्राप्त करने के लिए फिर से खोलना होगा ।

मैं जो बात कर रहा हूँ उसका एक छोटा सा उदाहरण:

int counter = 0;    

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

और फिर कॉलम और पॉप के माध्यम से चलने के लिए लूप

something.Read();

int dbFields = sqlRead.FieldCount;

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

जवाबों:


96

केवल दो विकल्प हैं:

  • सभी पंक्तियों को पढ़कर पता करें (और तब आप उन्हें स्टोर कर सकते हैं)

  • पहले से एक विशेष चयनित COUNT (*) क्वेरी चलाएँ।

DataReader लूप के माध्यम से दो बार जाना वास्तव में महंगा है, आपको क्वेरी को फिर से निष्पादित करना होगा।

और (पीट OHanlon के लिए धन्यवाद) दूसरा विकल्प केवल संगामिति-सुरक्षित है जब आप स्नैपशॉट अलगाव स्तर के साथ लेनदेन का उपयोग करते हैं।

चूंकि आप सभी पंक्तियों को स्मृति में संग्रहीत करना चाहते हैं, वैसे भी एकमात्र समझदार विकल्प एक लचीली भंडारण ( List<>या DataTable) में सभी पंक्तियों को पढ़ना है और फिर डेटा को किसी भी प्रारूप में कॉपी करना है जिसे आप चाहते हैं। इन-मेमोरी ऑपरेशन हमेशा बहुत अधिक कुशल होगा।


5
हेंक सही है: डेटारीडर का कोई सदस्य नहीं है जो आपको पंक्तियों की संख्या प्राप्त करने की अनुमति देता है क्योंकि यह एक आगे का केवल रीडर है। आप पहले गिनती प्राप्त करने और फिर क्वेरी निष्पादित करने से बेहतर हैं, शायद एक बहु-परिणाम क्वेरी में ताकि आप केवल डेटाबेस को एक बार हिट कर सकें।
flipdoubt

14
विशेष गणना के साथ समस्या यह है कि गणना की गई पंक्तियों की संख्या से भिन्न होने की संभावना है क्योंकि किसी और ने डेटा को इस तरह से बदल दिया है जिससे पंक्तियों की संख्या वापस आ जाती है।
पीट ओहनलान

1
पीट, तुम सही हो, यह एक महंगी अलगाव की आवश्यकता होगी।
हेन्क होल्टरमैन

1
आप सभी को धन्यवाद! यह और स्पष्ट होता जा रहा है। तो क्या सभी जानकारी को डेटासेट में डंप करना या SQL COUNT (*) के माध्यम से चलाना बेहतर है, इसे स्टोर करें और फिर आवश्यक क्वेरी चलाएं? या हम डेटासेट में गिनती चलाने और सब कुछ संग्रहीत करने के बारे में बात कर रहे हैं?
टॉमाज़ इनविक्ज़

4
एक RepeatableReadआइसोलेशन स्तर रेंज-लॉकिंग नहीं करता है, इसलिए यह अभी भी रिकॉर्ड सम्मिलित करने की अनुमति देता है, आपको एक आइसोलेशन स्तर का उपयोग करने की आवश्यकता है Snapshotया Serializable
लुकाज़ोइड

10

यदि आपको सभी पंक्ति को पुनः प्राप्त करने की आवश्यकता नहीं है और दोहरी क्वेरी बनाने से बचना चाहते हैं, तो आप शायद ऐसा कुछ आज़मा सकते हैं:

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

यदि आप उसी आदेश का पुन: उपयोग कर रहे हैं तो उस पर लेन-देन को स्वचालित रूप से जोड़ने पर आपको कोई लेन-देन सुनिश्चित नहीं करना पड़ सकता है ...


1
कोई भी कह सकता है अगर @@ ROWCOUNT हमेशा ऊपर चलने वाली अंतिम क्वेरी पर भरोसा करे? समस्याएँ यदि कई कनेक्शन क्वेरी समानांतर चलती हैं?
YvesR

1
क्या यह करना आवश्यक है sqlCon.Close();? मैंने सोचा कि usingइसे आपके लिए करना चाहिए।
नीले

1
यह तब काम नहीं करेगा जब पाठक से डेटा प्राप्त करने से पहले हमें
पंक्तिबद्ध

8

ऊपर, एक डेटासेट या टाइप किए गए डेटासेट एक अच्छी टेम्पोररी संरचना हो सकती है जिसका उपयोग आप अपने फ़िल्टरिंग को करने के लिए कर सकते हैं। एक SqlDataReader डेटा को बहुत तेज़ी से पढ़ने के लिए है। जब आप समय () लूप में होते हैं तब भी आप डीबी से जुड़े होते हैं और आपके द्वारा आगे बढ़ने से पहले अगले परिणाम को पढ़ने / संसाधित करने के लिए जो कुछ भी आप कर रहे हैं, उसका आपको इंतजार है। इस मामले में आपको बेहतर प्रदर्शन मिल सकता है यदि आप सभी डेटा में खींचते हैं, तो DB से कनेक्शन बंद करें और परिणाम "ऑफ़लाइन" संसाधित करें।

लोग डेटासेट से घृणा करने लगते हैं, इसलिए उपरोक्त को जोरदार टाइप की गई वस्तुओं के संग्रह के रूप में अच्छी तरह से किया जा सकता है।


2
मैं खुद को डेटासेट्स से प्यार करता हूं, क्योंकि वे टेबल-आधारित डेटा का एक अच्छी तरह से लिखित और बेहद उपयोगी सामान्य प्रतिनिधित्व हैं। अजीब रूप से पर्याप्त है, मैंने देखा है कि ज्यादातर लोग जो ORM के लिए डेटासेट से बचते हैं, वही लोग हैं जो अपने कोड को यथासंभव सामान्य (आमतौर पर व्यर्थ) होने के लिए लिखने की कोशिश करते हैं।
MusiGenesis

5
डैनियल, 'ऊपर' किसी अन्य उत्तर को संदर्भित करने का एक अच्छा तरीका नहीं है।
हेन्क होल्टरमैन

6

आप डेटा रीडर से सीधे पंक्तियों की एक गिनती प्राप्त नहीं कर सकते हैं क्योंकि यह वह है जिसे फायरहॉश कर्सर के रूप में जाना जाता है - जिसका अर्थ है कि रीड के आधार पर डेटा को पंक्ति के आधार पर पंक्ति में पढ़ा जाता है। मैं डेटा पर 2 रीड करने के खिलाफ सलाह दूंगा क्योंकि 2 रीड करने के बीच डेटा में परिवर्तन होने की संभावना है, और इस तरह आपको अलग-अलग परिणाम प्राप्त होंगे।

आप जो कर सकते थे, वह डेटा को एक अस्थायी संरचना में पढ़ा गया है, और दूसरे पढ़ने के स्थान पर इसका उपयोग करें। वैकल्पिक रूप से, आपको उस तंत्र को बदलना होगा जिसके द्वारा आप डेटा पुनर्प्राप्त करते हैं और इसके बजाय डेटाटेबल जैसी किसी चीज़ का उपयोग करते हैं।


5

गड्ढे के उत्तर को पूरा करने और बेहतर परिश्रम के लिए: सभी को एक क्वेरी में प्राप्त करें और 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();
}

1

मुझे एक ऐसी स्थिति का भी सामना करना पड़ता है जब मुझे एक शीर्ष परिणाम वापस करने की आवश्यकता होती है, लेकिन यह भी कुल पंक्तियों को प्राप्त करना चाहता है जहां क्वेरी से मेल खाते हैं। मैं इस समाधान के लिए अंतिम हो:

   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;
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.