Tengo un objeto de consulta SQLAlchemy y quiero obtener el texto de la declaración SQL compilada, con todos sus parámetros vinculados (por ejemplo, ninguna %s
u otras variables esperando ser vinculadas por el compilador de declaraciones o el motor de dialecto MySQLdb, etc.).
Invocar str()
la consulta revela algo como esto:
SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC
Intenté buscar en query._params pero es un dict vacío. Escribí mi propio compilador usando este ejemplo del sqlalchemy.ext.compiler.compiles
decorador, pero incluso la declaración allí todavía tiene %s
dónde quiero datos.
No puedo averiguar cuándo se mezclan mis parámetros para crear la consulta; al examinar el objeto de consulta, siempre son un diccionario vacío (aunque la consulta se ejecuta bien y el motor lo imprime cuando activa el registro de eco).
Estoy empezando a recibir el mensaje de que SQLAlchemy no quiere que conozca la consulta subyacente, ya que rompe la naturaleza general de la interfaz de la API de expresión en todas las diferentes DB-API. No me importa si la consulta se ejecuta antes de saber cuál era; ¡Sólo quiero saber!
fuente
c = q.statement.compile(...)
, puedes conseguirloc.params
as_scalar()
método -deQuery
.str(q)
.La documentación utiliza
literal_binds
para imprimir una consulta queq
incluye parámetros:La documentación también emite esta advertencia:
fuente
Esto debería funcionar con Sqlalchemy> = 0.6
fuente
adapt
de esta manera. Como mínimo, llame a prepare () en el valor de retorno de él cada vez, proporcionando la conexión como un argumento, para que pueda hacer las citas adecuadas.prepare
en el valor de retorno, sino que se parece que no tiene ese método:AttributeError: 'psycopg2._psycopg.AsIs' object has no attribute 'prepare'
. Estoy usando psycopg2 2.2.1 BTWPara el backend de MySQLdb modifiqué un poco la increíble respuesta de albertov (¡muchas gracias!). Estoy seguro de que podrían fusionarse para verificar si lo
comp.positional
fue,True
pero eso está un poco más allá del alcance de esta pregunta.fuente
return tuple(params)
funcionara como un encanto! Me salvaste incontables horas de tener que recorrer un camino extremadamente doloroso.La cosa es que sqlalchemy nunca mezcla los datos con su consulta. La consulta y los datos se pasan por separado a su controlador de base de datos subyacente; la interpolación de datos ocurre en su base de datos.
Sqlalchemy pasa la consulta como ha visto en
str(myquery)
la base de datos, y los valores irán en una tupla separada.Podría usar algún enfoque en el que interpole los datos con la consulta usted mismo (como albertov sugirió a continuación), pero eso no es lo mismo que está ejecutando sqlalchemy.
fuente
SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC
ES la consulta final. Esos%s
son enviados a la base de datos por sqlalchemy - sqlalchemy NUNCA coloca los datos reales en lugar de% ssqlalchemy.dialects.mysql.mysqldb
,do_executemany()
pasa la declaración y los parámetros por separado al cursor MySQLdb. yay indirección!Primero permítame un prefacio diciendo que supongo que está haciendo esto principalmente con fines de depuración; no recomendaría intentar modificar la declaración fuera de la API fluida de SQLAlchemy.
Desafortunadamente, no parece haber una forma sencilla de mostrar la declaración compilada con los parámetros de consulta incluidos. SQLAlchemy en realidad no pone los parámetros en la declaración, se pasan al motor de la base de datos como un diccionario . Esto permite que la biblioteca específica de la base de datos maneje cosas como escapar de caracteres especiales para evitar la inyección de SQL.
Pero puede hacer esto en un proceso de dos pasos con razonable facilidad. Para obtener la declaración, puede hacer lo que ya ha mostrado y simplemente imprimir la consulta:
Puede acercarse un paso más con query.statement, para ver los nombres de los parámetros. Nota a
:id_1
continuación frente a%s
arriba: no es realmente un problema en este ejemplo muy simple, pero podría ser clave en una declaración más complicada.Luego, puede obtener los valores reales de los parámetros obteniendo la
params
propiedad de la declaración compilada:Esto funcionó para un backend MySQL al menos; Esperaría que también sea lo suficientemente general para PostgreSQL sin necesidad de usar
psycopg2
.fuente
Para el backend de postgresql que usa psycopg2, puede escuchar el
do_execute
evento, luego usar el cursor, la declaración y escribir los parámetros forzados junto conCursor.mogrify()
para insertar los parámetros. Puede devolver True para evitar la ejecución real de la consulta.Uso de muestra:
fuente
La siguiente solución utiliza el lenguaje de expresión SQLAlchemy y funciona con SQLAlchemy 1.1. Esta solución no mezcla los parámetros con la consulta (como lo solicitó el autor original), pero proporciona una forma de utilizar modelos SQLAlchemy para generar cadenas de consulta SQL y diccionarios de parámetros para diferentes dialectos SQL. El ejemplo se basa en el tutorial. http://docs.sqlalchemy.org/en/rel_1_0/core/tutorial.html
Dada la clase,
podemos producir una declaración de consulta usando la función de selección .
A continuación, podemos compilar la declaración en un objeto de consulta.
De forma predeterminada, la declaración se compila utilizando una implementación básica 'nombrada' que es compatible con bases de datos SQL como SQLite y Oracle. Si necesita especificar un dialecto como PostgreSQL, puede hacer
O si desea especificar explícitamente el dialecto como SQLite, puede cambiar el estilo de parámetro de 'qmark' a 'named'.
Desde el objeto de consulta, podemos extraer la cadena de consulta y los parámetros de consulta.
y finalmente ejecutar la consulta.
fuente
Puede utilizar eventos de la familia ConnectionEvents :
after_cursor_execute
obefore_cursor_execute
.En sqlalchemy UsageRecipes de @zzzeek puede encontrar este ejemplo:
Aquí puede acceder a su estado de cuenta
fuente
Entonces, juntando un montón de pequeños fragmentos de estas diferentes respuestas, se me ocurrió lo que necesitaba: un conjunto simple de código para ingresar y ocasionalmente pero de manera confiable (es decir, maneja todos los tipos de datos) tomar el SQL compilado exacto enviado a mi Postgres backend con solo interrogar la consulta en sí:
fuente
Creo que .statement posiblemente haría el truco: http://docs.sqlalchemy.org/en/latest/orm/query.html?highlight=query
fuente