Reputation: 29
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:
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:
How can I get this result, any help please?
Upvotes: 0
Views: 4461
Reputation: 1
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
Open the file with Textpad.
Use the Mark feature of the Find dialog and Mark all lines with create procedure and EXEC .
Copy all bookmarked lines and past into a new document.
Use the replace feature to search for all EXEC and replace it with \nEXEC. be sure you check the box "Regular Expression".
You now have a list of stored procedures with any Execs indented beneath them. I guess you could use the same for inserts but that depends on how messy your SQL is.
Upvotes: -1
Reputation: 46241
One method to parse stored procedures is with the Microsoft.SqlServer.TransactSql.ScriptDom. This is used internally for functionality provided by some SQL Server tools.
This parser uses a visitor pattern to interpret the T-SQL abstract syntax tree. The basic C# example below may help you get started for your specific needs. 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.
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
Upvotes: 3