web-dev-qa-db-ja.com

Python

非リレーショナルデータストアの上にSQLインターフェイスを作成したいのですが。非リレーショナルデータストアですが、リレーショナルな方法でデータにアクセスすることは理にかなっています。

[〜#〜] antlr [〜#〜] を使用して、SQLを関係代数式として表すASTを生成することを検討しています。次に、木を評価/歩く。

これまでパーサーを実装したことがないので、SQLパーサーとエバリュエーターを最適に実装する方法についてアドバイスをお願いします。

  • 上記のアプローチは正しいように聞こえますか?
  • 調査すべき他のツール/ライブラリはありますか? [〜#〜] ply [〜#〜] または Pyparsing のように。
  • 私を助ける記事、本、またはソースコードへのポインタは高く評価されます。

更新:

Pyparsingを使用して単純なSQLパーサーを実装しました。 Pythonデータストアに対する関係演算を実装するコードと組み合わせると、これはかなり簡単でした。

コメントの1つで述べたように、この演習のポイントは、データをレポートエンジンで利用できるようにすることでした。これを行うには、おそらくODBCドライバを実装する必要があります。これはおそらく多くの作業です。

44
codeape

私はこの問題をかなり広範囲に調査しました。 Python-sqlparseは非検証パーサーであり、実際には必要ありません。 antlrの例では、PythonでNice astに変換するのに多くの作業が必要です。 SQL標準文法は here ですが、自分で変換するのはフルタイムの仕事であり、それらのサブセットのみ必要、つまり結合は必要ない可能性があります。 gadfly (a python sqlデータベース)も見てみることができますが、独自の解析ツールを使用していたので避けました。

私の場合、本質的に必要なのはwhere句だけです。私はpyparsingで書かれた booleneo (ブール式パーサー)を試しましたが、最初からpyparsingを使用してしまいました。 Mark Rushakoffのreddit投稿の最初のリンクは、それを使用したSQLの例を示しています。 Whoosh 全文検索エンジンもこれを使用しますが、ソースを調べてその方法を確認していません。

Pyparsingは非常に使いやすく、SQLとまったく同じにならないように非常に簡単にカスタマイズできます(ほとんどの構文は不要になります)。プライは命名規則を使用していくつかの魔法を使用するため、私はプライが好きではありませんでした。

つまり、pyparsを試してみると、必要なことを実行するのに十分強力である可能性が高く、python(簡単なコールバックとエラー処理付き)との単純な統合により、エクスペリエンスはかなり簡単になります。

37
David Raznick

このreddit投稿 は、他のいくつかのリンクの中で、既存の実装として Python-sqlparse を示唆しています。

11
Mark Rushakoff

TwoLaidのPython SQLパーサーは、私の目的には非常にうまく機能します。Cで書かれており、コンパイルする必要があります。堅牢です。各句の個々の要素を解析します。

https://github.com/TwoLaid/python-sqlparser

レポートヘッダーで使用するクエリの列名を解析するために使用しています。例を示します。

import sqlparser

def get_query_columns(sql):
   '''Return a list of column headers from given sqls select clause'''

   columns = []

   parser = sqlparser.Parser()

   # Parser does not like new lines
   sql2 = sql.replace('\n', ' ')

   # Check for syntax errors
   if parser.check_syntax(sql2) != 0:
      raise Exception('get_query_columns: SQL invalid.')

   stmt = parser.get_statement(0)
   root = stmt.get_root()
   qcolumns = root.__dict__['resultColumnList']
   for qcolumn in qcolumns.list:
      if qcolumn.aliasClause:
         alias = qcolumn.aliasClause.get_text()
         columns.append(alias)
      else:
         name = qcolumn.get_text()
         name = name.split('.')[-1] # remove table alias
         columns.append(name)

   return columns

sql = '''
SELECT 
   a.a,
   replace(coalesce(a.b, 'x'), 'x', 'y') as jim,
   a.bla as sally  -- some comment
FROM
   table_a as a
WHERE
   c > 20
'''

print get_query_columns(sql)

# output: ['a', 'jim', 'sally']
3
dlink

もちろん、活用するのが最善かもしれません Google Codeのpython-sqlparse

更新:これが提案されていることがわかりました-これは価値があると思います:

1
Barton