C# 使用正则表达式扫描T-SQL中的对象依赖项
我正在编写一个c类库,它允许我扫描SQL server查询并将查询中的对象提取到正确的分组中,例如:C# 使用正则表达式扫描T-SQL中的对象依赖项,c#,sql,regex,C#,Sql,Regex,我正在编写一个c类库,它允许我扫描SQL server查询并将查询中的对象提取到正确的分组中,例如: SELECT * FROM "My Server"."Northwind"."dbo"."Product Sales for 1997" Group By CategoryID 这个正则表达式将匹配上面的字符串,并将我的服务器、Northwind、dbo和1997年的产品销售分为四个组,这就是我想要的 (?i)\bFROM\b\s+[\["]([^\]"]*)[\]"].{1}[\["]([^
SELECT * FROM "My Server"."Northwind"."dbo"."Product Sales for 1997" Group By CategoryID
这个正则表达式将匹配上面的字符串,并将我的服务器、Northwind、dbo和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组->对象名称
我试图避免创建多个正则表达式来处理所有可能的组合,以避免我的类库变得太大和复杂,但是作为一个regexn00b,它被证明有点困难。使用regex可以做的最好的事情是将它解析为令牌,然后必须确定组的实际服务器数据库等是什么。下面是一个正则表达式,用于将数据示例转换为此类令牌。注意,我不知道sql server有引号,但您的示例要求使用引号,因此我使用If条件see my blog文章查找分别转义为\x22和\x27的单引号和双引号。标记被放入匹配捕获中,并在其中提取
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
*/
使用regex最好的方法是将其解析为令牌,然后必须确定组的实际服务器数据库等。下面是一个正则表达式,用于将数据示例转换为此类令牌。注意,我不知道sql server有引号,但您的示例要求使用引号,因此我使用If条件see my blog文章查找分别转义为\x22和\x27的单引号和双引号。标记被放入匹配捕获中,并在其中提取
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
*/
要解析任意SQL查询,最好使用一个。尝试用正则表达式解析任意SQL将等同于编写自己的解析器 在完整SQL解析器的帮助下,很容易实现所需的功能:
SELECT * FROM Northwind."My Schema"."My view or table function";
输出将如下所示:
select clause:
Columns
Fullname:*
Prefix: Column:* alias:
from clause:
Northwind."My Schema"."My view or table function"
database: Northwind
schema: "My Schema"
object: "My view or table function"
object alias:
您可以尝试自己测试更复杂的SQL查询。要解析任意SQL查询,最好使用一个。尝试用正则表达式解析任意SQL将等同于编写自己的解析器 在完整SQL解析器的帮助下,很容易实现所需的功能:
SELECT * FROM Northwind."My Schema"."My view or table function";
输出将如下所示:
select clause:
Columns
Fullname:*
Prefix: Column:* alias:
from clause:
Northwind."My Schema"."My view or table function"
database: Northwind
schema: "My Schema"
object: "My view or table function"
object alias:
您可以自己测试更复杂的SQL查询。正则表达式不适合这种情况。你需要一个解析器。e、 感谢您的快速响应,但是由于时间限制和编写解析器的复杂性,编写解析器是不可能的。我可以使用任何预先存在的T-SQL解析器吗?我确实成功地编写了正则表达式来从EXEC语句中提取组件,但只有在对象名称中没有空格时才有效。我很快意识到,要覆盖所有的组合,我最终会得到太多我真正想要的正则表达式。如果你不知道,请看OP的评论,我会看一看。非常感谢!解析器是一个好主意,但是如果您需要快速的正则表达式修复,从示例来看,当您有xxx.xxx.xxx.xxx时,它是0,1,2,3组;对于xxx.xxx.xxx,它是1,2,3;对于xxx.xx,它是2,3;xxx是3。然后您可以从\b\s+?:?:xx?xx?xx?xx?xx作为您的正则表达式,其中xx是您上面的正则表达式,[\[[^\]*[\].{1}。请注意,{1}是多余的。可以。正则表达式不适合这种情况。你需要一个解析器。e、 感谢您的快速响应,但是由于时间限制和编写解析器的复杂性,编写解析器是不可能的。我可以使用任何预先存在的T-SQL解析器吗?我确实成功地编写了正则表达式来从EXEC语句中提取组件,但只有在对象名称中没有空格时才有效。我很快意识到,要覆盖所有的组合,我最终会得到太多我真正想要的正则表达式。如果你不知道,请看OP的评论,我会看一看。非常感谢!解析器是一个好主意,但是如果您需要快速的正则表达式修复,从示例来看,当您有xxx.xxx.xxx.xxx时,它是0,1,2,3组;对于xxx.xxx.xxx,它是1,2,3;对于xxx.xx,它是2,3;xxx是3。然后您可以从\b\s+?:?:xx?xx?xx?xx?xx作为您的正则表达式,其中xx是您上面的正则表达式,[\[[^\]*[\].{1}。请注意,{1}是多余的。可以。