2010-05-31 14 views
6

से एसक्यूएल के लिए बैच विभाजक को सटीक रूप से कैसे संभाल सकता हूं, मैं बैच विभाजक के लिए समर्थन जोड़ना चाहता हूं।मैं <a href="http://cloudexchange.cloudapp.net/stackoverflow/query/new" rel="nofollow noreferrer">Data Explorer</a> के लिए सी #

तो उदाहरण के लिए अगर उन में टाइप करें:

 
select 'GO' go select 1 as go 
Go 
select 100 

मैं तीन परिणाम सेट वापस जाने के लिए चाहते हैं।

इसका स्पष्ट है कि मैं यहाँ पार्सर के कुछ प्रकार की जरूरत है

, मुझे आशा है (कुछ मैं करना चाहते हैं है एक पूर्ण T-SQL पार्सर नहीं लिख)

है कि यह एक हल समस्या है और मैं सिर्फ इसे प्लग कर सकते हैं। है

इस बैच को अपने 3 भागों में विभाजित करने वाला कौन सा घटक/डेमो कोड प्राप्त कर सकता है?

+0

चीज़ ... यह एक लागत 12k http: //www.temporal-wave .com/index.php? विकल्प = com_content & view = आलेख और आईडी = 48: sqlparser और catid = 35: उत्पादों और itemid = 53 –

+0

नोट: माइक्रोसॉफ्ट एक टीएसक्यूएल 100 पार्सर जहाज ... लेकिन मेरे जीवन के लिए मैं यह नहीं समझ सकता कि इसे बैच के साथ कैसे प्रदान किया जाए पहचानकर्ता ... मैं बहुत ही सीमित समाधान के बावजूद बस एक छोटा सा करने की ओर झुक रहा हूं। –

उत्तर

2

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

आगे बढ़ने के लिए अपने उपयोगकर्ताओं को ऐसे ही एक नियम का पालन नहीं कर सकते, तो एक आदेश के रूप में व्याख्या की जा करने के लिए,: इनपुट

का एक सरल नियम लागू क्या वे वास्तव में एसक्यूएल प्रश्न लिखने के कहीं अधिक जटिल कार्य में लगे रहेंगे?

+0

yerp यह है कि मैंने –

+0

https://docs.microsoft.com/en-us/sql/t से किया -एसक्ल/भाषा-तत्व/एसक्यूएल-सर्वर-यूटिलिटीज-स्टेटमेंट-गो, "एक ट्रांजैक्ट-एसक्यूएल कथन एक गो कमांड के समान लाइन पर कब्जा नहीं कर सकता है। हालांकि, लाइन में टिप्पणियां हो सकती हैं।" तो यह पहले से ही (लगभग) सच है। विपरीत मामला यह है कि मुझे क्या चिंता है: '' 'चुनें '\ n जाओ \ n';' '' 'टिप्पणियों में नई लाइनें नहीं डाल सकते हैं)। –

0

मुझे इस के मौजूदा समाधान से अवगत नहीं है (हालांकि मैं मानता हूं कि शायद वहां एक बाहर है)। मैं बस यह इंगित करना चाहता हूं कि आपको शायद एक पूर्ण टी-एसक्यूएल पार्सर लिखने की आवश्यकता नहीं है: आपको वास्तव में उद्धरण के बाहर "जाने" शब्द खोजने की ज़रूरत है। यही है, <word boundary>GO<word boundary> देखें और रास्ते में खुलने और समापन उद्धरणों का ट्रैक रखें। यदि आपको कोई मिलान मिलता है और यह एक उद्घाटन उद्धरण के बाद नहीं है (इसके मिलान बंद होने से पहले) तो यह बैच विभाजक है। यह कुछ भी लिखने के बिना ऐसा करना काफी आसान होना चाहिए जिसे आप उचित "पार्सर" कहते हैं।

+0

yerp यह काम कर सकता है लेकिन यह मुश्किल हो जाता है, उदाहरण के लिए: 1 के रूप में चयन करें वैध एसक्यूएल है mgmt स्टूडियो –

0

ऊपर दिए गए मामले में, क्या आप सिर्फ नई लाइनों पर विभाजित नहीं हो सकते हैं, अगर प्रत्येक शब्द का परीक्षण "जाने" के साथ शुरू होता है, तो उस पर स्क्रिप्ट को विभाजित करें?

इसे दो बार फिर से पढ़ने के बाद, यह वास्तव में बदसूरत समस्या है। आपकी लिपि में पहली पंक्ति को देखते हुए, वास्तव में कोई कमांड डिलीमीटर (अर्धविराम या न्यूलाइन) नहीं हैं। मुझे नहीं लगता कि आपके पास बहुत पसंद है लेकिन वास्तव में पूरी चीज़ को पार्स करने के लिए।

लेकिन, रेखा के साथ कहीं भी इसे किसी भी तरह से पार्स किया जाना है, है ना? शायद इसके लिए आप कुछ कर सकते हैं या इसके लिए मौजूदा पार्सर का उपयोग कर सकते हैं। पर कितना पहुँच आप इसे करने के लिए है, तो आप कर सकते थे निर्भर करता है:

  • बदलें "go" निष्पादित और वापस जाने यह क्या है के लिए आदेश को समझने के लिए मौजूदा पार्सर के लिए कोड है, तो फिर से चलाने के।

  • मौजूदा पार्स कोड की एक प्रति ले लो, अनुकूलन यह "जाना" कमांड को समझने के लिए, दुभाषिया भाग को निकाल देते हैं, तो बस ब्लॉक विभाजित है और असली पार्सर को खिलाने के लिए इसका इस्तेमाल करते हैं?

2

मैं एक ही समस्या का समाधान ढूंढ रहा था, लेकिन कोई उपयुक्त नहीं मिला (एसएमओ का उपयोग मेरे मामले में स्वीकार्य नहीं था)। तो, मुझे अपना पार्सर लिखना पड़ा।यहां यह है:

static IEnumerable<string> ParseSqlBatch(Stream s) 
{ 
    if (s == null) 
     throw new ArgumentNullException(); 

    StringBuilder sbSqlStatement = new StringBuilder(); 
    Stack<string> state = new Stack<string>(); 
    StreamReader sr = new StreamReader(s); 

    //initially search for "GO" or open tag of strings ('), comments (--, /*) or identifiers ([) 
    string pattern = @"(?>(?<=^\s*)go(?=\s*(--.*)?$)|''(?!')|(?<!')'|(?<!\[)\[|--(?=.*)?|/\*)"; 
    //if open tag found search for close tag, then continue search 
    string patternCloseString = @"(?>''|'(?!'))"; 
    string patternCloseIdentifier = @"(?>\]\]|\](?!\]))"; 
    string patternComments = @"(?>\*/|/\*)"; 

    Regex rx = new Regex(pattern, RegexOptions.IgnoreCase); 

    while (!sr.EndOfStream) 
    { 
     string line = sr.ReadLine(); 

     int ix = 0; 
     bool bBreak = false; 
     while (ix < line.Length && !bBreak) 
     { 
      Match m = rx.Match(line, ix); 

      if (!m.Success) 
      { 
       sbSqlStatement.Append(line.Substring(ix)); 
       break; 
      } 

      int ix2 = m.Index; 
      string word = m.Value; 

      sbSqlStatement.Append(line.Substring(ix, ix2 - ix)); 

      if (state.Count == 0) 
      { 
       if (string.Compare(word, "GO", true) == 0) 
       { 
        if (sbSqlStatement.Length > 0) 
        { 
         yield return sbSqlStatement.ToString(); 
         sbSqlStatement = new StringBuilder(); 
         break; 
        } 
       } 
       else 
       { 
        switch (word) 
        { 
         case "'": 
          rx = new Regex(patternCloseString); 
          break; 
         case "[": 
          rx = new Regex(patternCloseIdentifier); 
          break; 
         case "/*": 
          rx = new Regex(patternComments); 
          break; 
         case "--": 
          sbSqlStatement.Append(line.Substring(ix2)); 
          bBreak = true; 
          continue; 
        } 

        if (word != "''") 
         state.Push(word); 
       } 
      } 
      else 
      { 
       string st = state.Peek(); 

       switch (st) 
       { 
        case "'": 
         if (st == word) 
          state.Pop(); 
         break; 
        case "[": 
         if (word == "]") 
          state.Pop(); 
         break; 
        case "/*": 
         if (word == "*/") 
          state.Pop(); 
         else if (word == "/*") 
          state.Push(word); 
         break; 
       } 

       if (state.Count == 0) 
        rx = new Regex(pattern, RegexOptions.IgnoreCase); 
      } 

      ix = ix2 + word.Length; 
      sbSqlStatement.Append(word); 
     } 

     sbSqlStatement.AppendLine(); 
    } 

    if (sbSqlStatement.Length > 0) 
     yield return sbSqlStatement.ToString(); 
} 

यह सही ढंग से तारों, पहचानकर्ताओं और टिप्पणियों के भीतर "जाओ" को संभालता है। शायद आदर्श नहीं है, लेकिन सैकड़ों विभिन्न .sql स्क्रिप्ट पर सफलतापूर्वक परीक्षण किया गया।

और फिर, उदाहरण के लिए:

using (FileStream fs = new FileStream("SampleBatch.sql", FileMode.Open, FileAccess.Read)) 
{ 
    foreach (string statement in ParseSqlBatch(fs)) 
    { 
     //execute statement here, or do something with it 
    } 

    fs.Close(); 
} 

मुझे आशा है कि यह किसी को मदद मिलेगी।

+0

क्या यह संगत पहचानकर्ता/डबल-उद्धृत तारों को संभालता है? –

+0

@ArinTaylor, डबल-उद्धृत तारों के लिए - हाँ (मुझे बताएं कि यह सिंडैक्टिक रूप से सही कुछ नहीं है), उद्धृत पहचानकर्ताओं के लिए - मुझे लगता है, नहीं। यह 'टेबल बनाएं' जैसे मामलों को संभाल नहीं पाएगा "'। मैं हमेशा '[नाम]' -स्टाइल पहचानकर्ताओं का उपयोग करता हूं और कभी भी 'नाम' 'स्टाइल नहीं करता हूं, और कोड इसके लिए डिज़ाइन नहीं किया गया है। लेकिन उद्धृत पहचानकर्ताओं के समर्थन के लिए इसे आसानी से संशोधित किया जा सकता है। बस स्ट्रिंग के लिए इस्तेमाल किए जाने वाले कोड के माध्यम से कोड के माध्यम से ''' '' '' '' '' '' '' '' '' '' के माध्यम से जोड़ें। –

0

आप बहुत आसानी से एक खुला SqlConnection के लिए मौजूदा डेटाबेस बदल सकते हैं:

connection.ChangeDatabase("YourDB"); 

एक उदाहरण:

private static void ConctDatabase(string connectionString) 
{ 
    using (SqlConnection conn = new SqlConnection(connectionString)) 
    { 
     conn.Open(); 
     MessageBox.Show("Database: {0}", conn.Database); 
     conn.ChangeDatabase("Northwind"); 
     MessageBox.Show("Database: {0}", conn.Database); 
    } 
} 
संबंधित मुद्दे

 संबंधित मुद्दे