如何使用来自 pyparsing 的 select_parser.py 从 SQL 获取 table 名称?

How to get table names from SQL using select_parser.py from pyparsing?

当我使用此代码将 select_parser.py from pyparsing 和 运行 与 pyparsing 2.2.0 一起使用时:

query="select z.a, b from test_table left join test2_table where 1=1 and b in (select bb from foo)"
for key, val in select_stmt.parseString(query, parseAll=True).items():
    print "%s: %s" % (key, val)

我明白了

$ python select_parser.pyparsing.py
where_expr: [['1', '=', '1'], 'AND', ['b', 'IN', ['SELECT', [['bb']], 'FROM', 'foo']]]
from: [['test_table', ['LEFT', 'JOIN'], 'test2_table', []]]
columns: [['z.a'], ['b']]

虽然原定义中有命名元素"table":

single_source = ( (Group(database_name("database") + "." + table_name("table*")) | table_name("table*")) + 

没有以名称 "table" 出现的字典键。

也许 "from" 元素首先消耗了东西?我不明白命名元素如何填充的确切逻辑,而且我没有通过阅读文档(几次谈话等)得到一个清晰的想法。

如何使用 select_parser.py 获取 SQL 查询中的所有 table 名称?

注意:这里的正确答案是一个列表(或集合):test_table, test2_table, foo.

我可以浏览 "from" 和沟槽列表,但这看起来很老套,我不知道它是否可行,而且 pyparsing 似乎不应该如何工作。

我看到了 this question, this one, and this one,但我不明白他们是如何提供帮助的。

您链接到的示例代码包括对 runTests 的调用。这是一个很棒的工具,可以用来尝试不同的测试字符串,并为您的解析器编写单元测试。

在对 runTests 的调用中插入您的查询字符串时,我们得到以下输出:

select z.a, b from test_table left join test2_table where 1=1 and b in (select bb from foo)
['SELECT', [['z.a'], ['b']], 'FROM', ['test_table', ['LEFT', 'JOIN'], 'test2_table', []], 'WHERE', [['1', '=', '1'], 'AND', ['b', 'IN', ['SELECT', [['bb']], 'FROM', 'foo']]]]
- columns: [['z.a'], ['b']]
  [0]:
    ['z.a']
  [1]:
    ['b']
- from: [['test_table', ['LEFT', 'JOIN'], 'test2_table', []]]
  [0]:
    ['test_table', ['LEFT', 'JOIN'], 'test2_table', []]
    - table: [['test_table'], ['test2_table']]
      [0]:
        ['test_table']
      [1]:
        ['test2_table']
- where_expr: [['1', '=', '1'], 'AND', ['b', 'IN', ['SELECT', [['bb']], 'FROM', 'foo']]]
  [0]:
    ['1', '=', '1']
  [1]:
    AND
  [2]:
    ['b', 'IN', ['SELECT', [['bb']], 'FROM', 'foo']]
    [0]:
      b
    [1]:
      IN
    [2]:
      ['SELECT', [['bb']], 'FROM', 'foo']
      - columns: [['bb']]
        [0]:
          ['bb']
      - from: ['foo']
      - table: [['foo']]
        [0]:
          ['foo']

'table' 名称 在那里,但您必须对结构进行一些导航才能找到它们。这是一种方法:

result = select_stmt.parseString(query)
table_names = []
def visit_structure(struct):
    if 'table' in struct:
        table_names.extend(t[0] for t in struct.table)
    for substruct in struct:
        if isinstance(substruct, ParseResults):
            visit_structure(substruct)

visit_structure(result)
print(table_names)

给出:

['test_table', 'test2_table', 'foo']

为了将来列出已解析的数据,请使用 ParserElement.runTestsParseResults.dump 方法。