2

我试图解析数百个存储过程,以专门获取它们的输出变量“@FirstName”、它们使用哪些表以及它们从“MyTbl.FirstName”中提取哪些字段。我能够很容易地收集变量,但我在收集表名时遇到了麻烦。有人可以帮忙吗?

到目前为止,我已经能够通过使用 StreamReader 解析 SQL 文件并逐行收集信息来提取这些字段中的大部分,例如,如果一行包含输出,那么我知道该行中的第一个文本很可能是@多变的。

@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;
    }    
}

我认为这将与表别名匹配,因为大多数别名都是一个字母,后跟一个换行符,但到目前为止我还没有得到任何表名......有人知道吗?

4

2 回答 2

6

坦率地说,我认为您的解析想法不会走得太远。您正在对如何在每个过程中格式化代码做出非常大胆的假设。我对格式化非常细致,但我无法保证你在这么多程序中所依赖的那种一致性,即使我自己写了它们。

需要注意的是延迟名称解析可能会在后面咬你,并且依赖关系跟踪在 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 中列表:

     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,则几乎不可能剔除表/列名。

于 2013-04-04T00:23:02.267 回答
0

你可以使用正则表达式。例如对于像这样的字符串

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();
  }

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

于 2013-04-04T00:19:21.803 回答