2017-11-27 3 views
0

私はselect_parser.py from pyparsingを取り、このコードを使用して2.2.0をpyparsingでそれを実行します。pyparsingからselect_parser.pyを使用してSQLからテーブル名を取得するには?

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']] 

を得る:

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

「テーブル」という名前のdictキーはありません。

"from"要素が最初に消費された要素ですか?名前付き要素がどのように埋められているかについての正確な論理は理解できませんし、ドキュメントを読むことで明確なアイデアは得られていません(いくつかの講演など)。

select_parser.pyを使用してSQLクエリ内のすべてのテーブル名を取得するにはどうすればよいですか?

注:正解はリスト(またはセット)です:test_table、test2_table、foo。

私は "from"とditch listを通過することができましたが、それはハッキーなようですが、それがうまくいくかどうかわかりませんし、pyparsingが動作するようには思われません。

私はthis question,this oneおよびthis oneを参照していますが、ここでどのように役立つのか分かりません。

答えて

1

リンク先のサンプルコードには、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'] 

'テーブルの名前:

runTestsへの呼び出しでクエリ文字列を挿入し、我々はこの出力を取得しますそれらに着く。

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方法を利用することがここでは一つの方法です。

+0

ありがとうございます!私はrunTestsとdumpとその出力を見ましたが、1)struct.table形式について知らなかった、2)ツリーをたどるためのパラダイムを知らなかった。 – dfrankow

+0

名前付きの結果フィールドには、 'result [" name "]' dict-key表記法または 'result.name'オブジェクト属性表記法を使用してアクセスできます(dict表記は名前が存在しない場合はKeyErrorを送出し、 '')。詳細はこちらのオンラインドキュメント:https://pythonhosted.org/pyparsing/pyparsing.ParseResults-class.html。ツリーをトラバースする場合、これは 'parseString'から返されたネストされた解析データを歩いているだけです。部分式は 'Group'sのpyparsingで囲まれているので、解析された結果の中にサブ構造ができます。 – PaulMcG

関連する問題