Skip to main content
 首页 » 编程设计

c#之存储过程解析器

2024年11月01日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 中肯定远非完美 (see the workarounds I posted for keeping it accurate even in SQL Server 2008),这里有几个想法(它们也不完美,但它们肯定会减少白发):

  1. 通过使用目录 View 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,则几乎不可能剔除表/列名称。