Analyse SQL avec Python

Je veux créer une interface SQL au-dessus d'un magasin de données non relationnel. Magasin de données non relationnel, mais il est logique d'accéder aux données de manière relationnelle.

Je cherche à utiliser ANTLR pour produire un AST qui représente le SQL en tant qu'expression d'algèbre relationnelle. Ensuite, renvoyez les données en évaluant / marchant l'arbre.

Je n'ai jamais implémenté d'analyseur auparavant, et je voudrais donc quelques conseils sur la meilleure implémentation D'un analyseur SQL et évaluateur.

  • L'approche décrite ci-dessus semble-t-elle juste?
  • y a-t-il d'autres outils/bibliothèques dans lesquels je devrais regarder? Comme PLIS ou Pyparsing.
  • Les pointeurs vers des articles, des livres ou du code source qui m'aideront sont appréciés.

Mise à Jour:

J'ai implémenté un simple analyseur SQL en utilisant pyparsing. Combiné avec du code Python qui implémente les opérations relationnelles contre mon magasin de données, c'était assez simple.

Comme je l'ai dit dans l'un des commentaires, le but de l'exercice était de mettre les données à la disposition des moteurs de rapports. Pour ce faire, je devrai probablement implémenter un pilote ODBC. C'est probablement un beaucoup de travail.

39
demandé sur codeape 2009-09-08 20:42:03

4 réponses

J'ai examiné cette question assez longuement. Python-sqlparse est un analyseur Non validant qui n'est pas vraiment ce dont vous avez besoin. Les exemples dans antlr ont besoin de beaucoup de travail pour convertir en un bon ast en python. Les grammeurs standard sql sont ici, mais ce serait un travail à temps plein de les convertir vous-même et il est probable que vous n'auriez besoin que d'un sous-ensemble d'entre eux, c'est-à-dire pas de jointures. Vous pourriez essayer de regarder le gadfly (une base de données sql Python) aussi, mais je l'ai évité comme ils l'ont utilisé leur propre outil d'analyse.

Pour mon cas, je n'avais essentiellement besoin que d'une clause where. J'ai essayé booleneo (un analyseur d'expression booléenne) écrit avec pyparsing mais j'ai fini par utiliser pyparsing à partir de zéro. Le premier lien dans le post reddit de Mark Rushakoff donne un exemple sql en l'utilisant. Whoosh un moteur de recherche en texte intégral l'utilise également mais je n'ai pas regardé la source pour voir comment.

Pyparsing est très facile à utiliser et vous pouvez très facilement personnaliser pour ne pas être exactement la même chose que sql (la plupart de la syntaxe dont vous n'aurez pas besoin). Je n'ai pas aimé ply car il utilise de la magie en utilisant des conventions de nommage.

En bref, essayez pyparsing, il sera probablement assez puissant pour faire ce dont vous avez besoin et la simple intégration avec python (avec des rappels faciles et une gestion des erreurs) rendra l'expérience assez indolore.

35
répondu David Raznick 2015-02-12 06:22:44

Ce post de reddit suggère Python-sqlparse comme une implémentation existante, parmi quelques autres liens.

9
répondu Mark Rushakoff 2009-09-08 16:44:31

L'Analyseur Python SQL de TwoLaid fonctionne très bien pour mes besoins. Il est écrit en C et doit être compilé. Il est robuste. Il analyse les éléments individuels de chaque clause.

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

Je l'utilise pour analyser les noms de colonnes de requêtes à utiliser dans les en-têtes de rapport. Ici est un exemple.

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']
2
répondu dlink 2017-07-30 20:27:19

Bien sûr, il peut être préférable de tirer parti de python-sqlparse sur Google Code

UPDATE: maintenant, je vois que cela a été suggéré-je suis d'accord que cela vaut la peine:

1
répondu Barton 2014-06-26 13:18:35