简体   繁体   English

如何解析存储过程?

[英]How to parse stored procedure?

I have some complex procedure at MSSQL, single procedure file more than 1000 lines, and with multiple update/insert/delete operation, and I want to parse all of procedure to get operate table object, like as:我在 MSSQL 中有一些复杂的过程,单个过程文件超过 1000 行,并且有多个更新/插入/删除操作,我想解析所有过程以获取操作表对象,例如:

alter procedure UP_TestDemo
as
update dbo.Models set A = '1', B = '2' from Modules m where m.ID = '0001'
insert DB.dbo.emplyees( Name ) select Name from Person
 
Exec dbo.UP_LOG @ModifyDate = '05/04/2018'
...
go

Expected analytical results:预期分析结果:

  • Update Table: dbo.Models更新表:dbo.Models
  • Insert Table: DB.dbo.emplyees插入表:DB.dbo.emplyees
  • Execure SP: dbo.UP_LOG执行 SP:dbo.UP_LOG

How can I get this result, any help please?我怎样才能得到这个结果,请帮忙?

One method to parse stored procedures is with the Microsoft.SqlServer.TransactSql.ScriptDom .解析存储过程的一种方法是使用Microsoft.SqlServer.TransactSql.ScriptDom This is used internally for functionality provided by some SQL Server tools.这在内部用于某些 SQL Server 工具提供的功能。

This parser uses a visitor pattern to interpret the T-SQL abstract syntax tree.此解析器使用访问者模式来解释 T-SQL 抽象语法树。 The basic C# example below may help you get started for your specific needs.下面的基本 C# 示例可以帮助您开始满足您的特定需求。 Generic T-SQL parsing is non-trivial due to the breadth and flexibility of the language but you ought to be able to develop a suitable one for your use case.由于语言的广度和灵活性,通用 T-SQL 解析非常重要,但您应该能够为您的用例开发合适的解析。

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.TransactSql.ScriptDom;
using System.IO;
public static class ProcParser
{
    static void Main(string[] args)
    {

        var procDef = @"
alter procedure UP_TestDemo
as
update dbo.Models set A = '1', B = '2' from Modules m where m.ID = '0001'
insert DB.dbo.emplyees( Name ) select Name from Person

Exec dbo.UP_LOG @ModifyDate = '05/04/2018'
GO
";
        var statementTargets = ProcParser.GetStatementTargets(procDef);

        foreach(var statementTarget in statementTargets)
        {
            Console.WriteLine(statementTarget);
        }

    }

    public static List<String> GetStatementTargets(string storedProcedureDefinition)
    {

        StringReader reader = new StringReader(storedProcedureDefinition);

        //specify parser for appropriate SQL version
        var parser = new TSql140Parser(true);

        IList<ParseError> errors;
        TSqlFragment sqlFragment = parser.Parse(reader, out errors);

        if (errors.Count > 0)
        {
            throw new Exception("Error parsing stored procedure definition");
        }

        SQLVisitor sqlVisitor = new SQLVisitor();
        sqlFragment.Accept(sqlVisitor);

        return sqlVisitor.StatementTargets;

    }

}

internal class SQLVisitor : TSqlFragmentVisitor
{

    public List<String> StatementTargets = new List<String>();

    public override void ExplicitVisit(AlterProcedureStatement node)
    {
        node.AcceptChildren(this);
    }

    public override void ExplicitVisit(ExecuteStatement node)
    {
        ExecuteSpecification executeSpec = node.ExecuteSpecification;
        ExecutableProcedureReference executableEntity = (ExecutableProcedureReference)executeSpec.ExecutableEntity;
        var tokenText = getTokenText(executableEntity.ProcedureReference);
        StatementTargets.Add($"Execute SP: {tokenText}");
    }
    public override void ExplicitVisit(UpdateStatement node)
    {
        var tokenText = getTokenText(node.UpdateSpecification.Target);
        StatementTargets.Add($"Update Table: {tokenText}");
    }
    public override void ExplicitVisit(InsertStatement node)
    {
        var tokenText = getTokenText(node.InsertSpecification.Target);
        StatementTargets.Add($"Insert Table: {tokenText}");
    }
    public string getTokenText(TSqlFragment frag)
    {
        var sb = new StringBuilder();
        for(int i = frag.FirstTokenIndex; i <= frag.LastTokenIndex; ++i)
        {
            sb.Append(frag.ScriptTokenStream[i].Text);
        }
        return sb.ToString();

    }
}

Output:输出:

Update Table: dbo.Models
Insert Table: DB.dbo.emplyees
Execute SP: dbo.UP_LOG

If I may submit a humble suggestion.如果我可以提交一个不起眼的建议。

Acquire Textpad.获取文本板。

In SSMS, use the Object Explorer Details to select all your stored procedures, right click and select Script Stored Procedure As ->Create To -> File在 SSMS 中,使用 Object Explorer Details 选择所有存储过程,右键单击并选择 Script Stored Procedure As -> Create To -> File

Open the file with Textpad.使用 Textpad 打开文件。

Use the Mark feature of the Find dialog and Mark all lines with create procedure and EXEC .使用 Find 对话框的 Mark 功能并使用create procedureEXEC标记所有行。

Copy all bookmarked lines and past into a new document.将所有书签行和过去复制到一个新文档中。

Use the replace feature to search for all EXEC and replace it with \\nEXEC.使用替换功能搜索所有 EXEC 并将其替换为 \\nEXEC。 be sure you check the box "Regular Expression".确保选中“正则表达式”框。

You now have a list of stored procedures with any Execs indented beneath them.您现在有一个存储过程列表,其中任何 Exec 都缩进在它们下方。 I guess you could use the same for inserts but that depends on how messy your SQL is.我想您可以将相同的内容用于插入,但这取决于您的 SQL 有多混乱。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM