正则表达式查找查询中的所有表名

时间:2008-11-11 14:38:00

标签: .net sql regex

我对正则表达式并不热衷,这让我的小脑袋融化了一些东西。

我试图在查询中查找所有表名。所以说我有查询:

SELECT one, two, three FROM table1, table2 WHERE X=Y

我想拉出“table1,table2”或“table1”和“table2”

但是如果没有where声明怎么办?它可能是文件的结尾,或者可能有一个组或一个顺序等。我知道“大多数”时间这不会是一个问题,但我不喜欢编码“最”的想法情况和知道我留下了一个可能导致事情出错的漏洞。

这是一个可行的正则表达式吗?我是正则表达式吗?

(P.S。这将在C#中完成,但假设无关紧要。)

12 个答案:

答案 0 :(得分:13)

RegEx对此不是很擅长,因为它比看起来要复杂得多:

  • 如果他们使用LEFT / RIGHT INNER / OUTER / CROSS / MERGE / NATURAL连接而不是a,b语法怎么办?无论如何都应该避免使用a,b语法。
  • 嵌套查询怎么样?
  • 如果没有表(选择常量)
  • 怎么办?
  • 换行符和其他空格格式怎么样?
  • 别名?

我可以继续。

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

答案 1 :(得分:5)

所有内容都说明了这种正则表达式在SQL上下文中的用处。如果你坚持使用正则表达式,你的SQL语句总是看起来像你显示的那个(这意味着没有子查询,连接等),你可以使用

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

答案 2 :(得分:3)

我参加派对的时间已经很晚了,但是我想我会分享一个正在使用的正则表达式来分析我们所有的数据库对象,而且我不同意这种情况,即不可能使用一个这样做。

正则表达式有一些假设

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

2)无论你使用什么正则表达式解析器都支持忽略大小写。

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

我很想知道这个表是什么类型的交易,所以我已经包含了Named Capture小组来告诉我。

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

\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

答案 3 :(得分:2)

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

http://www.sqlparser.com/

非常值得。是一种享受。

答案 4 :(得分:2)

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

例如:

SELECT tbltable1.one, tbltable1.two, tbltable2.three
FROM tbltable1
    INNER JOIN  tbltable2
        ON tbltable1.one = tbltable2.three

将空格拆分为数组:

("SELECT","tbltable1.one,","tbltable1.two,","tbltable2.three","FROM","tbltable1","INNER","JOIN","tbltable2","ON","tbltable1.one","=","tbltable2.three")

将元素留给句号:

("SELECT","tbltable1","tbltable1","tbltable2","FROM","tbltable1","INNER","JOIN","tbltable2","ON","tbltable1","=","tbltable2")

删除带符号的元素:

("SELECT","tbltable1","tbltable1","tbltable2","FROM","tbltable1","INNER","JOIN","tbltable2","ON","tbltable1","tbltable2")

降低到唯一值:

("SELECT","tbltable1","tbltable2","FROM","INNER","JOIN","ON")

过滤左3个字符= "tbl"

("tbltable1","tbltable2")

答案 5 :(得分:1)

这绝对不容易。

考虑子查询。

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)

此查询中使用了三个表。

答案 6 :(得分:1)

我认为将字符串标记化并查找可能绑定表名的SQL关键字会更容易。您知道这些名称会跟随FROM,但WHEREGROUP BYHAVING或者根本没有关键字,如果它们位于查询。

答案 7 :(得分:0)

构建正则表达式将是您遇到的最少问题。根据您希望使用此代码支持的SQL的风格,您可以在SQL语句中引用表的方式数量是惊人的。

PLUS,如果查询包含对视图或UDF的引用,则有关基础表甚至不在字符串中的信息,通过解析它来获取该信息是完全不切实际的。此外,您需要聪明地检测临时表并将其从结果中排除。

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

如果您正在使用SQL Server,那么这篇文章是关于检测该平台上的依赖关系的:Finding Dependencies in SQL Server 2005

答案 8 :(得分:0)

这将在插入到查询中拉出表名:

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

以下将执行相同操作,但选择包括连接

(?<=(from|join)\s)[^\s]*(?=\s(on|join|where))

如果只想返回插入查询中保存的值,最后返回插入使用以下正则表达式

(?i)(?<=VALUES[ ]*\().*(?=\))

我知道这是一个旧帖子,但它可以帮助其他人环顾

享受

答案 9 :(得分:0)

我尝试了以上所有但是没有用,因为我使用了各种各样的查询。我正在使用PHP并使用一个名为SQL_Parser的PEAR库,但希望我的解决方案有所帮助。此外,我在使用撇号和MySQL保留sencences时遇到了麻烦,因此我决定在解析之前从查询中删除所有字段部分。

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;

}

答案 10 :(得分:0)

在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命名

我希望它适合你

答案 11 :(得分:0)

我使用此代码作为Excel宏来解析select和extract表名。

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

只需针对您的SQL查询运行它,如果您对结果不满意,那么您应该只有几行代码,而不是您期望的结果。只需相应地调试和修改代码。

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