3

我需要为 C# 构建一个正则表达式,以便捕获 select 子句中“from”关键字之后的所有表名。例如

.
.
.
SELECT field1, field2
FROM table1
WHERE condition1
.
.
.
SELECT field3, field4
FROM table2
WHERE condition2
.
.
.

我尝试读取的文件中有多个 select 子句,并且 select 和 from 之间可以有任何字符(包括换行符、':'、'_' 和任何其他字符)。我应该如何构建我的正则表达式以获取所有表名?

谢谢

编辑: 我找到了一种获取所有表名的方法。

\s*SELECT[^;]*FROM\s*(?<key>[^\n]*)

这可能会在某一天帮助某人。谢谢

4

3 回答 3

3

除非所有查询都只有一个表并且没有有趣的评论业务,否则使用正则表达式是一个失败的提议。反而:

SET SHOWPLAN_ALL ON;

--All your queries here

请参阅设置 showplan_all文档。

当我说正则表达式会变得复杂时,这就是我的意思。这些只是一些考虑因素:

  • 您必须检测带引号的字符串的开头:", ',[并忽略其中的所有字符,直到正确终止。如果结束字符加倍,则不要终止(即'this is ''fun'', he said'在 之后不停止is)。

  • --您必须排除不在引号内的单行注释,并在下一个 CRLF 处终止它们。注释中的引号不会像往常一样开始字符串。

  • 您必须排除/*不在引号内或单行注释内的多行注释(以 开头),然后跳过除终止符 . 之外的所有其他内容*/。在您的正则表达式中,请务必*使用反斜杠转义字符\

  • 然后,您必须找到具有正确单词边界的有效子句(例如FROM,列名SelfRom或没有错误匹配)。AfroMonkey

  • 要正确终止 FROM 子句,您必须在看到任何关键字时停止捕获,包括WHEREGROUP BYHAVINGORDER BYWITH; 并且由于 SQL 查询不需要有分号终止符,;那么您还必须在SELECT, DBCC, SET, CREATE,等处终止。ALTERDROP

  • 但即使是前两点本身也不够,因为如果您的查询如下所示:

    SELECT *
    FROM
       MyTable T
       INNER JOIN (
          SELECT * FROM YourTable Y WHERE Active = 1
       ) X ON T.ID = Y.ID
       INNER JOIN AnotherTable A
          ON X.AID = A.AID
    

    现在,您必须解析括号,并且在看到任何这些关键字时不要停止捕获 FROM 子句。而且你必须跟踪你有多少括号,并一直忽略,直到你有那么多括号。最后,你如何处理这些,因为派生表就像一个表——你想要派生表的全​​文还是里面的表?

为此,您不能只从FROM文本中的第一个有效字符开始匹配,因为这可能在引号或注释中。您必须匹配从头开始的所有文本,因为这是使用正则表达式确保您找不到不应该匹配的唯一方法。

这是我想出的只是尝试处理评论的方法。甚至没有引号。它只能找到from子句,而不是里面的内容。另外,我们必须防止括号被捕获,这样在检查我们的捕获组以获取实际的 FROM 子句时,我们不会遇到可怕的混乱。

(?:(?:-(?!-)|/(?!\*)|f(?!rom)|[^-f/])|--[^\n]*\n|/\*(?:\*/)*\*/)*from()

而且它可能充满了错误,一旦我玩了一点,我就不得不重新考虑整个事情,总而言之,这将是巨大的时间浪费。

我认为您低估了要做好这样的事情的难度。但是有一个完全可靠的解决方案!我在上面给出的那个:让 SQL Server 为您解析所有内容。您可以轻松解析返回的计划,因为它的结构很容易。

于 2012-12-20T10:01:05.993 回答
1

首先我想说看看这个教程: http: //www.codeproject.com/Articles/9099/The-30-Minute-Regex-Tutorial

查看这样的正则表达式:((?<=FROM )[^\s]+)

此正则表达式将在"FROM "(包括空格)之后直接开始读取,并在第一个空格处停止读取(^\s)

如果你尝试这样的事情

foreach (Match m in Regex.Matches(input, @"((?<=FROM )[^\s]+)")
{
    string output = m.Value;
}

编辑:

我不是 100% 确定这个正则表达式。如果您的名称末尾有换行符,这可能会做得更好:@"((?<=FROM)[^\n]+))但您可能应该修剪输出,因为输出字符串的开头可能有一个空格。

于 2012-12-20T09:41:19.970 回答
0
var input = "select name from Table1 where id =2";
var pattern = @"from\s*(.*?)\s*where"; // where car= is the first delimiter and ; is the second one
var result = Regex.Match(input, pattern).Groups[1].Value;
MessageBox.Show(result);
于 2012-12-20T09:45:01.050 回答