Analizando SQL con Python

Quiero crear una interfaz SQL encima de un almacén de datos no relacionales. Almacén de datos no relacionales, pero tiene sentido acceder a los datos de manera relacional.

Estoy estudiando el uso de ANTLR para producir un AST que represente el SQL como una expresión de álgebra relacional. Luego devuelva los datos evaluando / caminando el árbol.

Nunca he implementado un analizador antes y, por lo tanto, me gustaría recibir algunos consejos sobre la mejor manera de implementar un analizador y evaluador de SQL.

  • ¿El enfoque descrito anteriormente suena bien?
  • ¿Hay otras herramientas / bibliotecas que debería estudiar? Como PLY o Pyparsing .
  • Se agradecen los punteros a artículos, libros o código fuente que me ayudarán.

Actualizar:

Implementé un analizador de SQL simple utilizando pyparsing. Combinado con el código Python que implementa las operaciones relacionales en mi almacén de datos, esto fue bastante simple.

Como dije en uno de los comentarios, el objective del ejercicio era poner los datos a disposición de los motores de informes. Para hacer esto, probablemente necesitaré implementar un controlador ODBC. Esto es probablemente mucho trabajo.

He examinado este tema bastante extensamente. Python-sqlparse es un analizador sin validación que no es realmente lo que necesita. Los ejemplos en antlr necesitan mucho trabajo para convertirse en un ast agradable en python. Los grammers estándar de sql están aquí , pero sería un trabajo de tiempo completo convertirlos usted mismo y es probable que solo necesite un subconjunto de ellos, es decir, que no haya uniones. También puedes intentar ver el gadfly (una base de datos de python sql), pero lo evité porque usaban su propia herramienta de análisis.

Para mi caso, esencialmente solo necesitaba una cláusula where. Probé booleneo (un analizador de expresiones booleanas) escrito con pyparsing pero terminé usando pyparsing desde cero. El primer enlace en la publicación de reddit de Mark Rushakoff da un ejemplo de sql usándolo. Whoosh un motor de búsqueda de texto completo también lo usa, pero no he mirado la fuente para ver cómo.

Pyparsing es muy fácil de usar y puedes personalizarlo fácilmente para que no sea exactamente igual a sql (la mayor parte de la syntax que no necesitarás). No me gustó la capa, ya que usa algo de magia usando las convenciones de nombres.

En pocas palabras, intente realizar una prueba de pyparsing, lo más probable es que sea lo suficientemente potente como para hacer lo que necesita y la sencilla integración con python (con devoluciones de llamadas sencillas y manejo de errores) hará que la experiencia sea bastante sencilla.

Esta publicación de reddit sugiere Python-sqlparse como una implementación existente, entre un par de otros enlaces.

El analizador de SQL Python de TwoLaid funciona muy bien para mis propósitos. Está escrito en C y necesita ser comstackdo. Es robusto. Analiza los elementos individuales de cada cláusula.

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

Lo estoy usando para analizar los nombres de las columnas de consultas para usar en los encabezados de los informes. Aquí hay un ejemplo.

 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 aa, replace(coalesce(ab, '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'] 

Por supuesto, puede ser mejor aprovechar Python-sqlparse en Google Code

ACTUALIZACIÓN: Ahora veo que esto ha sido sugerido, estoy de acuerdo en que vale la pena: