csharp 解析通过T-SQL从连接子句推断外键 - 注意:不完整。只支持seroc中的sprocs和一些语法结构
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了csharp 解析通过T-SQL从连接子句推断外键 - 注意:不完整。只支持seroc中的sprocs和一些语法结构相关的知识,希望对你有一定的参考价值。
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Data.Schema.ScriptDom;
using Microsoft.Data.Schema.ScriptDom.Sql;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Joins
{
class ForeignKey
{
public string Table1 { get; set; }
public string Key1 { get; set; }
public string Table2 { get; set; }
public string Key2 { get; set; }
}
class StatementContext
{
public Dictionary<string, string> Aliases {get;set;}
public List<ForeignKey> FKs { get; set; }
public StatementContext()
{
Aliases = new Dictionary<string, string>();
FKs = new List<ForeignKey>();
}
public void Alias(TableSource ts)
{
if (ts.GetType() == typeof(SchemaObjectTableSource))
{
var source = ts as SchemaObjectTableSource;
if (source.Alias != null)
{
var alias = source.Alias.Value.ToLower();
if (!Aliases.ContainsKey(alias))
Aliases.Add(alias, source.SchemaObject.BaseIdentifier.Value);
}
}
}
public string UnAlias(string s)
{
if (Aliases.ContainsKey(s.ToLower()))
return Aliases[s.ToLower()];
else
return s;
}
}
class Program
{
static void Main(string[] args)
{
string filePath = args[0];
string Script = string.Empty;
//System.Diagnostics.Debugger.Break();
using (StreamReader streamReader = new StreamReader(filePath))
{
Script = streamReader.ReadToEnd();
}
IList<string> errorsList;
var TSqlScript = ParseScript(Script, out errorsList);
foreach (var b in TSqlScript.Batches)
SearchStatmentList(b.Statements);
}
private static void SearchStatement(TSqlStatement s)
{
if (s != null)
{
var t = TextFrom(s);
var st = s.GetType();
if (st == typeof(AlterProcedureStatement))
SearchStatmentList((((AlterProcedureStatement)s).StatementList.Statements));
else if (st == typeof(CreateProcedureStatement))
SearchStatmentList((((CreateProcedureStatement)s).StatementList.Statements));
else if (st == typeof(BeginEndBlockStatement))
SearchStatmentList((((BeginEndBlockStatement)s).StatementList.Statements));
else if (st == typeof(InsertStatement))
{
var i = (InsertStatement)s;
if (i.InsertSource.GetType() == typeof(SelectStatement))
SearchStatement(i.InsertSource as SelectStatement);
}
else if (st == typeof(IfStatement))
{
var i = s as IfStatement;
SearchStatement(i.ThenStatement);
SearchStatement(i.ElseStatement);
}
else if (st == typeof(SelectStatement))
{
FindFromClauses(((SelectStatement)s).QueryExpression);
}
}
}
private static void SearchStatmentList(IList<TSqlStatement> statements)
{
foreach (var s in statements)
SearchStatement(s);
}
private static void FindFromClauses(QueryExpression q)
{
if (q.GetType() == typeof(BinaryQueryExpression))
{
var binary = q as BinaryQueryExpression;
FindFromClauses(binary.FirstQueryExpression);
FindFromClauses(binary.SecondQueryExpression);
}
else if (q.GetType() == typeof(QuerySpecification))
{
var qs = q as QuerySpecification;
var t = TextFrom(q);
foreach (var from in qs.FromClauses)
{
if (from.GetType() == typeof(QualifiedJoin))
{
StatementContext ctx = new StatementContext();
WalkJoin(from as QualifiedJoin, ctx);
foreach (var r in ctx.FKs)
{
Console.WriteLine(string.Format("{0}.{1} = {2}.{3}", ctx.UnAlias(r.Table1), r.Key1, ctx.UnAlias(r.Table2), r.Key2));
}
}
}
}
}
private static void WalkJoin(QualifiedJoin j, StatementContext context)
{
var t = TextFrom(j);
if (j.SearchCondition.GetType() == typeof(BinaryExpression))
{
var b = j.SearchCondition as BinaryExpression;
t = TextFrom(b);
context.Alias(j.FirstTableSource);
context.Alias(j.SecondTableSource);
if (b.BinaryExpressionType == BinaryExpressionType.Equals)
{
if (b.FirstExpression.GetType() == typeof(Column) &&
b.SecondExpression.GetType() == typeof(Column))
{
context.FKs.Add(new ForeignKey()
{
Table1 = ((Column)b.FirstExpression).Identifiers[0].Value,
Key1 = ((Column)b.FirstExpression).Identifiers[1].Value,
Table2 = ((Column)b.SecondExpression).Identifiers[0].Value,
Key2 = ((Column)b.SecondExpression).Identifiers[1].Value
});
}
}
if (j.FirstTableSource.GetType() == typeof(QualifiedJoin))
{
WalkJoin((QualifiedJoin)j.FirstTableSource, context);
}
if (j.SecondTableSource.GetType() == typeof(QualifiedJoin))
{
WalkJoin((QualifiedJoin)j.SecondTableSource, context);
}
}
}
private static string TextFrom(TSqlFragment f)
{
if (f == null) return null;
var sb = new StringBuilder();
for (int i = f.FirstTokenIndex; i <= f.LastTokenIndex; i++)
{
sb.Append(f.ScriptTokenStream[i].Text);
}
return sb.ToString();
}
public static TSqlScript ParseScript(string script, out IList<string> errorsList)
{
IList<ParseError> parseErrors;
TSql100Parser tsqlParser = new TSql100Parser(true);
TSqlFragment fragment;
using (StringReader stringReader = new StringReader(script))
{
fragment = (TSqlFragment)tsqlParser.Parse(stringReader, out parseErrors);
}
errorsList = new List<string>();
if (parseErrors.Count > 0)
{
var retMessage = string.Empty;
foreach (var error in parseErrors)
{
retMessage += error.Identifier + " - " + error.Message + " - position: " + error.Offset + "; ";
}
}
return (TSqlScript)fragment;
}
}
}
以上是关于csharp 解析通过T-SQL从连接子句推断外键 - 注意:不完整。只支持seroc中的sprocs和一些语法结构的主要内容,如果未能解决你的问题,请参考以下文章