Executing SQL batch containing GO statements in C#

前端 未结 3 502
[愿得一人]
[愿得一人] 2020-12-30 15:37

I am trying to build a program which execute sql statements in batch with error handling (therefore I am not using SMO).

the problem is that GO is not a part

3条回答
  •  太阳男子
    2020-12-30 16:04

    ScriptDom

    The easiest solution (and the most robust) is to use a T-SQL parser. The good news is that you don't have to write it, just add reference to:

    • Microsoft.Data.Schema.ScriptDom
    • Microsoft.Data.Schema.ScriptDom.Sql

    Then use the code:

    static void Main(string[] args)
    {
        string sql = @"
    /* 
    GO
    */ 
    SELECT * FROM [table]
    
    GO
    
    SELECT * FROM [table]
    SELECT * FROM [table]
    
    GO
    
    SELECT * FROM [table]";
    
        string[] errors;
        var scriptFragment = Parse(sql, SqlVersion.Sql100, true, out errors);
        if (errors != null)
        {
            foreach (string error in errors)
            {
                Console.WriteLine(error);
                return;
            }
        }
    
        TSqlScript tsqlScriptFragment = scriptFragment as TSqlScript;
        if (tsqlScriptFragment == null)
            return;
    
        var options = new SqlScriptGeneratorOptions { SqlVersion = SqlVersion.Sql100, KeywordCasing = KeywordCasing.PascalCase };
    
        foreach (TSqlBatch batch in tsqlScriptFragment.Batches)
        {
            Console.WriteLine("--");
            string batchText = ToScript(batch, options);
            Console.WriteLine(batchText);                
        }
    }
    
    public static TSqlParser GetParser(SqlVersion level, bool quotedIdentifiers)
    {
        switch (level)
        {
            case SqlVersion.Sql80:
                return new TSql80Parser(quotedIdentifiers);
            case SqlVersion.Sql90:
                return new TSql90Parser(quotedIdentifiers);
            case SqlVersion.Sql100:
                return new TSql100Parser(quotedIdentifiers);
            case SqlVersion.SqlAzure:
                return new TSqlAzureParser(quotedIdentifiers);
            default:
                throw new ArgumentOutOfRangeException("level");
        }
    }
    
    public static IScriptFragment Parse(string sql, SqlVersion level, bool quotedIndentifiers, out string[] errors)
    {
        errors = null;
        if (string.IsNullOrWhiteSpace(sql)) return null;
        sql = sql.Trim();
        IScriptFragment scriptFragment;
        IList errorlist;
        using (var sr = new StringReader(sql))
        {
            scriptFragment = GetParser(level, quotedIndentifiers).Parse(sr, out errorlist);
        }
        if (errorlist != null && errorlist.Count > 0)
        {
            errors = errorlist.Select(e => string.Format("Column {0}, Identifier {1}, Line {2}, Offset {3}",
                                                            e.Column, e.Identifier, e.Line, e.Offset) +
                                                Environment.NewLine + e.Message).ToArray();
            return null;
        }
        return scriptFragment;
    }
    
    public static SqlScriptGenerator GetScripter(SqlScriptGeneratorOptions options)
    {
        if (options == null) return null;
        SqlScriptGenerator generator;
        switch (options.SqlVersion)
        {
            case SqlVersion.Sql80:
                generator = new Sql80ScriptGenerator(options);
                break;
            case SqlVersion.Sql90:
                generator = new Sql90ScriptGenerator(options);
                break;
            case SqlVersion.Sql100:
                generator = new Sql100ScriptGenerator(options);
                break;
            case SqlVersion.SqlAzure:
                generator = new SqlAzureScriptGenerator(options);
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
        return generator;
    }
    
    public static string ToScript(IScriptFragment scriptFragment, SqlScriptGeneratorOptions options)
    {
        var scripter = GetScripter(options);
        if (scripter == null) return string.Empty;
        string script;
        scripter.GenerateScript(scriptFragment, out script);
        return script;
    }
    

    SQL Server Management Objects

    Add references to:

    • Microsoft.SqlServer.Smo
    • Microsoft.SqlServer.ConnectionInfo
    • Microsoft.SqlServer.Management.Sdk.Sfc

    You can then use this code:

    using (SqlConnection connection = new SqlConnection("Server=(local);Database=Sample;Trusted_Connection=True;"))
    {
        ServerConnection svrConnection = new ServerConnection(connection);
        Server server = new Server(svrConnection);
        server.ConnectionContext.ExecuteNonQuery(script);
    }
    

    CodeFluent Runtime

    CodeFluent Runtime Database has a small sql file parser. It does not handle complex cases but for instance comments are supported.

    using (StatementReader statementReader = new CodeFluent.Runtime.Database.Management.StatementReader("GO", Environment.NewLine, inputStream))
    {
        Statement statement;
        while ((statement = statementReader.Read(StatementReaderOptions.Default)) != null)
        {
            Console.WriteLine("-- ");
            Console.WriteLine(statement.Command);
        }
    }
    

    Or much simplier

    new CodeFluent.Runtime.Database.Management.SqlServer.Database("connection string")
          .RunScript("path", StatementReaderOptions.Default);
    

提交回复
热议问题