Skip to main content
 首页 » 编程设计

c#之使用正则表达式扫描 T-SQL 的对象依赖关系

2024年01月11日42jillzhang

我正在编写一个 c# 类库,它将允许我扫描 SQL 服务器查询并将查询中的对象提取到正确的分组中,例如:

SELECT * FROM "My Server"."Northwind"."dbo"."Product Sales for 1997" Group By CategoryID 

此正则表达式将匹配上面的字符串并将“My Server”、“Northwind”、“dbo”和“Product Sales for 1997”分为四组,这正是我想要的。

(?i)\bFROM\b\s+[\["]([^\]"]*)[\]"].{1}[\["]([^\]"]*)[\]"].{1}[\["]([^\]"]*)[\]"].{1}[\["]([^\]"]*)[\]"].{1} 

我正在寻找的是一个正则表达式,它可以捕获以下任何组合的服务器名称、数据库名称、模式名称和对象名称(这无论如何都不是详尽的列表):

SELECT * FROM dbo."Product Sales for 1997" // should return groups 2 & 3 
SELECT * FROM Northwind."My Schema"."My view or table function" // should return  groups 1, 2 & 3 
SELECT * FROM "My view or table function" // should return group 3 
SELECT * FROM dbo."My View 1" AS V1 JOIN "My View 1" AS V2 ON V1.ID = V2 // should return groups 2 & 3 

换句话说,我想将各种组件分为以下几组:

组 0 --> 服务器名称
第 1 组 --> 数据库名称
第 2 组 --> 架构
第 3 组 --> 对象名称

我试图避免创建多个正则表达式来处理所有可能的组合,以避免我的类库变得太大和太复杂,但作为正则表达式 n00b,它被证明有点困难。

请您参考如下方法:

使用正则表达式可以做的最好的事情是将其解析为标记,然后必须确定组的实际情况(服务器数据库等)是什么。这是一个正则表达式,用于将您的数据示例放入此类标记中。请注意,我不知道 sql server 有引号,但您的示例要求它们,所以我使用 If 条件查找分别转义为\x22 和\x27 的单引号和双引号(请参阅我的博客文章 Regular Expressions and the If Conditional )。 token 被放置在提取它们的匹配捕获中。

string data = 
@"SELECT * FROM dbo.""Product Sales for 1997"" // should return groups 2 & 3  
SELECT * FROM Northwind.""My Schema"".""My view or table function"" // should return  groups 1, 2 & 3  
SELECT * FROM ""My view or table function"" // should return group 3  
SELECT * FROM dbo.""My View 1"" AS V1 JOIN ""My View 1"" AS V2 ON V1.ID = V2 // should return groups 2 & 3 "; 
 
string pattern =  
@" 
(?:FROM\s+)                 # Work from a from only 
( 
  (?([\x27\x22])            # If a single or double quote is found       
     (?:[\x27\x22]) 
       (?<Tokens>[\w\s]+)   # process quoted text 
     (?:[\x27\x22]\.?) 
   |                        # else 
     (?!\s+AS|\s+WHERE)     # if AS or Where is found stop the match we are done 
     (?:\.?) 
     (?<Tokens>\w+)         # Process non quoted token. 
     (?:\.?) 
   ) 
   (?![\n\r/])              # Stop on CR/LF or a comment.  
){0,4}                      # Only do this 1 to 4 times, for it can't be more (parser hint to stop) 
"; 
 
Regex.Matches(data, pattern, RegexOptions.IgnorePatternWhitespace) // Ignore is to allow commenting of the pattern only (not data processing) 
    .OfType<Match>() 
    .Select(mt => mt.Groups["Tokens"] 
                    .Captures.OfType<Capture>() 
                    .Select(cp => cp.Value)) 
    .ToList() // To do the foreach below 
    .ForEach(tokens => Console.WriteLine(string.Join(" | ", tokens))); 
 
/* Output 
dbo | Product Sales for 1997 
Northwind | My Schema | My view or table function 
My view or table function 
dbo | My View 1 
*/