.net 用于查找查询中所有表名的正则表达式

.net 用于查找查询中所有表名的正则表达式,.net,sql,regex,.net,Sql,Regex,我对正则表达式不太感兴趣,它让我的小脑袋融化了一些什么 我正在尝试查找查询中的所有表名。假设我有疑问: SELECT one, two, three FROM table1, table2 WHERE X=Y 我想把“表1、表2”或“表1”和“表2”拉出来 但是如果没有where语句呢。它可能是文件的结尾,也可能是一个群组或一个订单等。我知道“大多数”时间这不会是一个问题,但我不喜欢为“大多数”情况编码的想法,我知道我留下了一个漏洞,可能会导致以后出问题 这是一个可行的正则表达式吗?我是一个雷

我对正则表达式不太感兴趣,它让我的小脑袋融化了一些什么

我正在尝试查找查询中的所有表名。假设我有疑问:

SELECT one, two, three FROM table1, table2 WHERE X=Y
我想把“表1、表2”或“表1”和“表2”拉出来

但是如果没有where语句呢。它可能是文件的结尾,也可能是一个群组或一个订单等。我知道“大多数”时间这不会是一个问题,但我不喜欢为“大多数”情况编码的想法,我知道我留下了一个漏洞,可能会导致以后出问题

这是一个可行的正则表达式吗?我是一个雷格斯普莱布吗


(顺便说一句,这将在C语言中完成,但假设这并不重要)。

这绝对不容易

考虑子查询

select
  *
from
  A
  join (
    select
       top 5 *
    from
      B)
    on B.ID = A.ID
where
  A.ID in (
    select
      ID
    from
      C
    where C.DOB = A.DOB)

此查询中使用了三个表。

我认为标记字符串并查找可以绑定表名的SQL关键字会更容易。您知道名称将跟在中的
,但它们后面可能跟在
WHERE
groupby
HAVING
,或者如果它们位于查询的末尾,则根本没有关键字。

RegEx在这方面做得不是很好,因为它比看起来复杂得多:

  • 如果他们使用左/右内/外/交叉/合并/自然连接而不是a,b语法,会怎么样?无论如何都应该避免使用a,b语法
  • 嵌套查询呢
  • 如果没有表格(选择常量),该怎么办
  • 换行符和其他空白格式呢
  • 别名
我可以继续


你可以做的是寻找一个sql解析器,并通过它运行你的查询。

所有关于这种正则表达式在sql上下文中的有用性的说法。如果您坚持使用正则表达式,并且您的SQL语句总是与您显示的语句类似(这意味着没有子查询、联接等),那么您可以使用

FROM\s+([^ ,]+)(?:\s*,\s*([^ ,]+))*\s+ 

我发现这个网站有一个很棒的解析器


很值得。工作是一种享受。

我参加聚会已经很晚了,但是我想我会共享一个正则表达式,我目前正在使用它来分析我们所有的数据库对象,我不同意这样的看法,即使用一个正则表达式是不可能的

正则表达式有一些假设

1) 您没有使用A,B连接语法样式

2) 您使用的任何正则表达式解析器都支持忽略大小写

3) 您正在分析、选择、连接、更新、删除和截断。它不支持前面提到的MERGE/NATURAL,因为我们不使用它们,但是我相信进一步的支持不会很难添加

我很想知道该表属于哪种类型的事务,所以我加入了命名的捕获组来告诉我

现在我已经很长时间没有使用regex了,所以可能会有一些改进,但是到目前为止,在我所有的测试中,这是准确的

\bjoin\s+(?<Retrieve>[a-zA-Z\._\d]+)\b|\bfrom\s+(?<Retrieve>[a-zA-Z\._\d]+)\b|\bupdate\s+(?<Update>[a-zA-Z\._\d]+)\b|\binsert\s+(?:\binto\b)?\s+(?<Insert>[a-zA-Z\._\d]+)\b|\btruncate\s+table\s+(?<Delete>[a-zA-Z\._\d]+)\b|\bdelete\s+(?:\bfrom\b)?\s+(?<Delete>[a-zA-Z\._\d]+)\b
(2)北京市政府建筑工地施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工现场施工a-zA-Z\.\ud]+)\b
构造正则表达式将是您的最小问题。根据您希望用这段代码支持的SQL的风格,在SQL语句中引用表的方法数量惊人

另外,如果查询包含对视图或UDF的引用,那么关于底层表的信息根本不会出现在字符串中,这使得通过解析来获取该信息完全不切实际。此外,您还需要明智地检测临时表并将其从结果中排除

如果必须这样做,更好的方法是将API用于SQL所针对的特定数据库引擎。例如,您可以基于查询创建一个视图,然后使用DB Server api检测该视图的依赖关系。DB引擎将能够比以往任何时候都更可靠地解析它,而无需花费大量精力对查询引擎进行反向工程


如果您正在使用SQL Server,这里有一篇关于检测该平台上的依赖关系的文章:

这将在insert Into查询中提取一个表名:

(?<=(INTO)\s)[^\s]*(?=\(())

(?我尝试了以上所有方法,但没有一种有效,因为我使用了各种各样的查询。不过我正在使用PHP,并使用了一个名为SQL\u Parser的PEAR库,但希望我的解决方案能有所帮助。此外,我在使用撇号和MySQL保留字符时遇到问题,所以我决定在解析查询之前从查询中删除所有字段部分

function getQueryTable ($query) {
    require_once "SQL/Parser.php";
    $parser = new SQL_Parser();
    $parser->setDialect('MySQL');

    // Stripping fields section
    $queryType = substr(strtoupper($query),0,6);            
    if($queryType == 'SELECT') { $query  = "SELECT * ".stristr($query, "FROM"); }
    if ($havingPos = stripos($query, 'HAVING')) { $query = substr($query, 0, $havingPos); }


    $struct = $parser->parse($query);

    $tableReferences = $struct[0]['from']['table_references']['table_factors'];

    foreach ((Array) $tableReferences as $ref) {
        $tables[] = ($ref['database'] ? $ref['database'].'.' : $ref['database']).$ref['table'];
    }

    return $tables;

}

在PHP中,我使用此函数,它返回一个数组,其中包含sql语句中使用的表名:

function sql_query_get_tables($statement){
    preg_match_all("/(from|into|update|join) [\\'\\´]?([a-zA-Z0-9_-]+)[\\'\\´]?/i",
            $statement, $matches);
    if(!empty($matches)){
        return array_unique($matches[2]);
    }else return array();
}
请注意,它不适用于a、b联接或schema.tablename命名


我希望它对您有用

一个解决方法是在表和视图上实现命名约定。然后可以在命名前缀上解析SQL语句

例如:

SELECT tbltable1.one, tbltable1.two, tbltable2.three
FROM tbltable1
    INNER JOIN  tbltable2
        ON tbltable1.one = tbltable2.three
将空白拆分为数组:

(“选择”、“tbltable1.1”、“tbltable1.2”、“tbltable2.3”、“从”、“tbltable1”、“内部”、“连接”、“tbltable2”、“打开”、“tbltable1.1”、“=”、“tbltable2.3”)

将元素左移到周期:

(“选择”、“tbltable1”、“tbltable1”、“tbltable2”、“来自”、“tbltable1”、“内部”、“加入”、“tbltable2”、“打开”、“tbltable1”、“=”、“tbltable2”)

删除带有符号的元素:

(“选择”、“tbltable1”、“tbltable1”、“tbltable2”、“来自”、“tbltable1”、“内部”、“加入”、“tbltable2”、“打开”、“tbltable1”、“tbltable2”)

减少到唯一值:

(“选择”、“tbltable1”、“tbltable2”、“来自”、“内部”、“加入”、“打开”)

左边3个字符的过滤器=
“tbl”


(“tbltable1”、“tbltable2”)
我将此代码用作Excel宏来解析select和extract表名

我的分析假设未使用语法
select from a,b,c

就跟它对抗吧
function sql_query_get_tables($statement){
    preg_match_all("/(from|into|update|join) [\\'\\´]?([a-zA-Z0-9_-]+)[\\'\\´]?/i",
            $statement, $matches);
    if(!empty($matches)){
        return array_unique($matches[2]);
    }else return array();
}
SELECT tbltable1.one, tbltable1.two, tbltable2.three
FROM tbltable1
    INNER JOIN  tbltable2
        ON tbltable1.one = tbltable2.three
Sub get_tables()
    sql_query = Cells(5, 1).Value
    tables = ""

    'get all tables after from
    sql_from = sql_query

    While InStr(1, UCase(sql_from), UCase("from")) > 0

        i = InStr(1, UCase(sql_from), UCase("from"))
        sql_from = Mid(sql_from, i + 5, Len(sql_from) - i - 5)
        i = InStr(1, UCase(sql_from), UCase(" "))

        While i = 1

            sql_from = Mid(sql_from, 2, Len(sql_from) - 1)
            i = InStr(1, UCase(sql_from), UCase(" "))

        end

        i = InStr(1, sql_join, Chr(9))

        While i = 1

            sql_join = Mid(sql_join, 2, Len(sql_join) - 1)
            i = InStr(1, sql_join, Chr(9))

        end

        a = InStr(1, UCase(sql_from), UCase(" "))
        b = InStr(1, sql_from, Chr(10))
        c = InStr(1, sql_from, Chr(13))
        d = InStr(1, sql_from, Chr(9))

        MinC = a

        If MinC > b And b > 0 Then MinC = b
        If MinC > c And c > 0 Then MinC = c
        If MinC > d And d > 0 Then MinC = d

        tables = tables + "[" + Mid(sql_from, 1, MinC - 1) + "]"

    end

    'get all tables after join
    sql_join = sql_query

    While InStr(1, UCase(sql_join), UCase("join")) > 0

        i = InStr(1, UCase(sql_join), UCase("join"))
        sql_join = Mid(sql_join, i + 5, Len(sql_join) - i - 5)
        i = InStr(1, UCase(sql_join), UCase(" "))

        While i = 1

            sql_join = Mid(sql_join, 2, Len(sql_join) - 1)
            i = InStr(1, UCase(sql_join), UCase(" "))

        end

        i = InStr(1, sql_join, Chr(9))

        While i = 1

            sql_join = Mid(sql_join, 2, Len(sql_join) - 1)
            i = InStr(1, sql_join, Chr(9))

        end

        a = InStr(1, UCase(sql_join), UCase(" "))
        b = InStr(1, sql_join, Chr(10))
        c = InStr(1, sql_join, Chr(13))
        d = InStr(1, sql_join, Chr(9))

        MinC = a

        If MinC > b And b > 0 Then MinC = b
        If MinC > c And c > 0 Then MinC = c
        If MinC > d And d > 0 Then MinC = d

        tables = tables + "[" + Mid(sql_join, 1, MinC - 1) + "]"

    end

    tables = Replace(tables, ")", "")
    tables = Replace(tables, "(", "")
    tables = Replace(tables, " ", "")
    tables = Replace(tables, Chr(10), "")
    tables = Replace(tables, Chr(13), "")
    tables = Replace(tables, Chr(9), "")
    tables = Replace(tables, "[]", "")

End Sub