Cómo ver la consulta SQL real en Python cursor.execute utilizando pyodbc y MS-Access

Uso el siguiente código en Python (con pyodbc para una base de MS-Access).

cursor.execute("select a from tbl where b=? and c=?", (x, y)) 

Está bien, pero, para fines de mantenimiento, necesito conocer la cadena de SQL completa y exacta que se envía a la base de datos.
¿Es posible y cómo?

Se diferencia por conductor. Aquí hay dos ejemplos:

 import MySQLdb mc = MySQLdb.connect() r = mc.cursor() r.execute('select %s, %s', ("foo", 2)) r._executed "select 'foo', 2" import psycopg2 pc = psycopg2.connect() r = pc.cursor() r.execute('select %s, %s', ('foo', 2)) r.query "select E'foo', 2" 

La respuesta es no. Publico mi pregunta en el código de Google principal del proyecto (y en el Grupo de Google) y la respuesta es:

Comentario # 1 sobre el problema 163 por l … @ deller.id.au: cursor.mogrify devolver cadena de consulta http://code.google.com/p/pyodbc/issues/detail?id=163

Para referencia, aquí hay un enlace a la documentación pyscopg de su método de cursor “mogrify” al que se refiere el informador: http://initd.org/psycopg/docs/cursor.html#cursor.mogrify

pyodbc no realiza ninguna de estas traducciones del SQL: pasa el SQL parametrizado directamente al controlador ODBC de forma literal. El único procesamiento involucrado es traducir los parámetros de los objetos de Python a los tipos de C admitidos por la API de ODBC.

Se puede realizar alguna transformación en el SQL en el controlador ODBC antes de que se envíe al servidor (por ejemplo, Microsoft SQL Native Client lo hace) pero estas transformaciones están ocultas para pyodbc.

Por consiguiente, creo que no es factible proporcionar una función de mogrificación en pyodbc.

Puede usar print cursor._last_executed para obtener la última consulta ejecutada.

Lea en esta respuesta que también puede usar print cursor.mogrify(query,list) para ver la consulta completa antes o después de la ejecución.

Para depurar purpuse he creado una función de verificación que simplemente reemplaza? con los valores de consulta … no es alta tecnología 🙂 pero funciona! :RE

 def check_sql_string(sql, values): unique = "%PARAMETER%" sql = sql.replace("?", unique) for v in values: sql = sql.replace(unique, repr(v), 1) return sql query="""SELECT * FROM dbo.MA_ItemsMonthlyBalances WHERE Item = ? AND Storage = ? AND FiscalYear = ? AND BalanceYear = ? AND Balance = ? AND BalanceMonth = ?""" values = (1,2,"asdasd",12331, "aas)",1) print(check_sql_string(query,values)) 

El resultado:

SELECT * FROM dbo.MA_ItemsMonthlyBalances WHERE Item = 1 AND Storage = 2 AND FiscalYear = ‘asdasd’ AND BalanceYear = 12331 AND Balance = ‘aas’) AND BalanceMonth = 1

Con esto puedes iniciar sesión o hacer lo que quieras:

 rowcount = self.cur.execute(query,values).rowcount logger.info(check_sql_string(query,values)) 

Si necesita simplemente añadir alguna excepción a la captura de la función.

Dependiendo del controlador que use, esto puede o no ser posible. En algunas bases de datos, los parámetros ( ? S) simplemente se reemplazan, como sugiere la respuesta del usuario 589983 (aunque el controlador tendrá que hacer algunas cosas, como citar cadenas y evadir comillas dentro de esas cadenas, para obtener una statement ejecutable).

Otros controladores le pedirán a la base de datos que compile (“prepare”) la statement, y luego le pedirá que ejecute la instrucción preparada usando los valores dados. De esta manera, el uso de sentencias preparadas o parametrizadas ayuda a evitar las inyecciones de SQL: en el momento en que se ejecuta la sentencia, la base de datos “sabe” qué es parte del SQL que desea ejecutar y qué es parte de un valor que se utiliza dentro de esa afirmación

A juzgar por un rápido repaso de la documentación de PyODBC , no parece que sea posible ejecutar el SQL real, pero puedo estar equivocado.

Revisé cursor._last_executed después, pero si quieres que se impriman en tiempo real sin cambiar cada ejecución, prueba este parche de mono:

 def log_queries(cur): def _query(q): print q # could also use logging return cur._do_query(q) cur._query = _query conn = MySQLdb.connect( read_default_file='~/.my.cnf' ) cur = conn.cursor() log_queries(cur) cur.execute('SELECT %s, %s, %s', ('hello','there','world')) 

Es muy dependiente de MySQLdb (y podría irrumpir en versiones posteriores). Funciona porque cur._query actualmente simplemente llama a calls._do_query y devuelve su resultado.

Escribe la cadena SQL y luego ejecútala:

 sql='''select a from tbl where b=? and c=? ''' cursor.execute(sql, x, y) print 'just executed:',(sql, x,y) 

Ahora puedes hacer lo que quieras con la sentencia SQL.