存储过程解析器
本文关键字:存储过程 | 更新日期: 2023-09-27 18:07:14
我正试图解析数百个存储过程,以专门抓取它们的输出变量"@FirstName",它们使用哪些表,以及它们从"MyTbl.FirstName"中提取哪些字段。我能够很容易地收集变量,但我有麻烦收集表名。有人能帮忙吗?
到目前为止,我已经能够通过使用StreamReader解析SQL文件并逐行收集信息来提取大部分字段,例如,如果一行包含输出,那么我知道该行中的第一个文本很可能是@Variable。@Address1 varchar(45) output,
@Address2 varchar(45) output,
@City varchar(35) output,
@State varchar(2) output,
@Zip varchar(10) output
从那里我可以将@Variable存储到字典中,如果任何一行包含@Variable并且还包含'=',那么我知道我们有一个匹配它对应的字段。
@Address1 = c.Address,
@Address2 = c.AddressSecondLine,
@City = c.City,
@State = c.State,
@Zip = c.ZipOrPostalCode
现在我只是有问题收集表名。我可以很容易地解析表别名字段名,但我有问题匹配别名与表名。有人知道一个好的方法吗?以下是我到目前为止一直在尝试的:
FROM Table.dbo.SalesStuff ss
LEFT OUTER JOIN Table.dbo.Customer c ON ss.CustNo = c.CustNo
Left JOIN Table.dbo.Vending v on @tmpVin = v.vin
代码 :
keyColl = tables.Keys;
foreach (string var in keyColl)
{
if (line.Contains(" " + var + ''r') || line.Contains(" " + var + " ") || line.Contains(" " + var + ((char)13)) || line.Contains(" " + var + Environment.NewLine))
{
tables[var] = line.ToString();
break;
}
}
我认为这将匹配表别名,因为大多数别名是一个字母,后跟一个换行符,但到目前为止,我还没有能够得到任何表名…有人知道吗?
坦率地说,我认为您的解析思想不会走得太远。您对每个过程中的代码如何格式化做出了非常大胆的假设。我对格式非常小心,但我无法保证你所依赖的那种一致性,即使我确实自己写了那么多程序。
需要注意的是,延迟名称解析可能会给你带来麻烦,而且依赖项跟踪在SQL Server 2005中也远非完美(参见我发布的在SQL Server 2008中保持准确的解决方案),这里有一些想法(它们也不完美,但它们肯定会减少白发):
-
通过使用目录视图
,您可以以比暴力解析更简单的方式获得参数。sys.parameters
:SELECT OBJECT_NAME([object_id]), p.name, t.name FROM sys.parameters AS p INNER JOIN sys.types AS t ON p.system_type_id = t.system_type_id WHERE p.is_output = 1;
-
如果您的所有过程都已重新编译,并且您没有受到延迟名称解析问题的影响,那么您可以从
sys.sql_dependencies
中获得表名和列名-但是这将包括在where/join子句中引用的列,即使它们不在选择列表中:SELECT [procedure] = OBJECT_NAME(d.[object_id]), [table] = OBJECT_NAME(d.referenced_major_id), [column] = c.name FROM sys.sql_dependencies AS d INNER JOIN sys.columns AS c ON c.[object_id] = d.referenced_major_id AND c.column_id = d.referenced_minor_id;
这里有一个叫做is_selected
的专栏,但我发现它不准确/可靠。
请注意,动态SQL中发生的任何事情都保留在动态SQL中-因此,如果您的过程使用动态SQL,则几乎不可能剔除表/列名。
可以使用正则表达式。例如对于像
这样的字符串FROM Table.dbo.SalesStuff ss
可以用
string pattern = @"'s*FROM's+Table'.dbo'.('w+)'s+('w+)";
string input = "line from stored proc body here";
MatchCollection matches = Regex.Matches(input, pattern);
foreach (Match match in matches)
{
Console.WriteLine("table name: {0}", match.Groups[1].Value);
Console.WriteLine("Alias: {0}", match.Groups[2].Value);
Console.WriteLine();
}
必须为包含表名和别名的每种类型的字符串定义模式