存储过程解析器

本文关键字:存储过程 | 更新日期: 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中保持准确的解决方案),这里有一些想法(它们也不完美,但它们肯定会减少白发):

  1. 通过使用目录视图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;
    
  2. 如果您的所有过程都已重新编译,并且您没有受到延迟名称解析问题的影响,那么您可以从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();
  }

必须为包含表名和别名的每种类型的字符串定义模式