【问题标题】:How do you parse large SQL scripts into batches?如何将大型 SQL 脚本解析成批处理?
【发布时间】:2013-04-22 14:42:45
【问题描述】:

我有一个非常大的 sql 文件,我想分批执行。 我想确保我以与 SSMS 和 SQLCMD 相同的方式解析它。

Microsoft 有一个名为 Microsoft.SqlServer.BatchParser 的出色混合模式程序集,其中有一个名为 Parser 的类,它的接缝就像它可以解决问题一样。

它希望在调用 Parse() 之前将 IBatchSource 的实现作为 SetBatchSource 的参数。

在哪里可以找到 IBatchSource 的实现,以及有关如何使用此功能的更多信息?

【问题讨论】:

    标签: c# .net sql-server tsql parsing


    【解决方案1】:

    我在 GAC 中找到了 Microsoft.SqlServer.BatchParser 程序集以及它的朋友 Microsoft.SqlServer.BatchParserClient,其中包含接口 IBatchSource 的实现。

    namespace Microsoft.SqlServer.Management.Common
    {
      internal class BatchSourceFile : IBatchSource
      internal class BatchSourceString : IBatchSource
    }
    

    随后发生了以下对话。

    大会:你好!我的名字是 Microsoft.SqlServer.Management.Common.ExecuteBatch。是否要 StringCollection GetStatements(string sqlCommand)?

    我: 是的,我愿意,BatchParserClient 程序集。谢谢提问!

    可重复的说明(在家试试这个!)

    • 安装Microsoft SQL Server 2008 R2 Shared Management Objects
    • 将 Microsoft.SqlServer.BatchParser.dll 和 Microsoft.SqlServer.BatchParserClient.dll 从 GAC 复制到解决方案中的文件夹。
    • 参考 Microsoft.SqlServer.BatchParser & Microsoft.SqlServer.BatchParserClient

    Program.cs

    using System;
    using System.Collections.Specialized;
    using System.IO;
    using System.Text;
    using Microsoft.SqlServer.Management.Common;
    
    namespace ScriptParser
    {
       class Program
       {
          static void Main(string[] args)
          {
             ExecuteBatch batcher = new ExecuteBatch();
             string text = File.ReadAllText(@"Path_To_My_Long_Sql_File.sql");
             StringCollection statements = batcher.GetStatements(text);
             foreach (string statement in statements)
             {
                Console.WriteLine(statement);
             }
          }
       }
    }
    

    App.Config

    <?xml version="1.0"?>
    <configuration>
       <startup useLegacyV2RuntimeActivationPolicy="true">
          <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
       </startup>
    </configuration>
    

    另一种选择是使用 ScriptDom,如此答案中所述:https://stackoverflow.com/a/32529415/26877

    using System;
    using System.Collections.Generic;
    using System.IO;
    using Microsoft.SqlServer.TransactSql.ScriptDom;
    
    namespace ScriptDomDemo
    {
        class Program
        {
            static void Main(string[] args)
            {
                TSql120Parser parser = new TSql120Parser(false);
                IList<ParseError> errors;
                using (StringReader sr = new StringReader(@"create table t1 (c1 int primary key)
    GO
    create table t2 (c1 int primary key)"))
                {
                    TSqlFragment fragment = parser.Parse(sr, out errors);
                    IEnumerable<string> batches = GetBatches(fragment);
                    foreach (var batch in batches)
                    {
                        Console.WriteLine(batch);
                    }
                }
            }
    
            private static IEnumerable<string> GetBatches(TSqlFragment fragment)
            {
                Sql120ScriptGenerator sg = new Sql120ScriptGenerator();
                TSqlScript script = fragment as TSqlScript;
                if (script != null)
                {
                    foreach (var batch in script.Batches)
                    {
                        yield return ScriptFragment(sg, batch);
                    }
                }
                else
                {
                    // TSqlFragment is a TSqlBatch or a TSqlStatement
                    yield return ScriptFragment(sg, fragment);
                }
            }
    
            private static string ScriptFragment(SqlScriptGenerator sg, TSqlFragment fragment)
            {
                string resultString;
                sg.GenerateScript(fragment, out resultString);
                return resultString;
            }
        }
    }
    

    【讨论】:

    • 抱歉,File.ReadAllText 仍然会先将整个文件读入内存。因此,对于大文件(可能大得不合理,但仍然如此),您会遇到问题。基本上,需要一个“流”接口。正如我所指出的over hereSQLCMD.EXE 能够做到这一点,并且大概也使用IBatchSource,尽管是本机实现而不是“托管”包装器。问题仍然存在:如何将输入文本拆分成块,以便 BatchParser 可以理解它。 (虽然仍然 +1,但贡献很大)
    • @Christian.K 找到答案 stackoverflow.com/a/32529415/26877,这可能是使用 ScriptDOM 解析批次的一个选项。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-15
    • 2020-01-31
    • 1970-01-01
    相关资源
    最近更新 更多