Ich habe ein SQLAlchemy-Abfrageobjekt und möchte den Text der kompilierten SQL-Anweisung mit allen gebundenen Parametern %s
abrufen (z. B. keine oder andere Variablen, die darauf warten, vom Anweisungscompiler oder der MySQLdb-Dialekt-Engine usw. gebunden zu werden).
Das Aufrufen str()
der Abfrage zeigt ungefähr Folgendes:
SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC
Ich habe versucht, in query._params zu suchen, aber es ist ein leeres Diktat. Ich habe meinen eigenen Compiler anhand dieses Beispiels des sqlalchemy.ext.compiler.compiles
Dekorateurs geschrieben, aber selbst die dortige Anweisung enthält noch %s
Daten.
Ich kann nicht genau herausfinden, wann meine Parameter zum Erstellen der Abfrage gemischt werden. Bei der Untersuchung des Abfrageobjekts handelt es sich immer um ein leeres Wörterbuch (obwohl die Abfrage einwandfrei ausgeführt wird und die Engine sie ausdruckt, wenn Sie die Echoanmeldung aktivieren).
Ich bekomme allmählich die Meldung, dass SQLAlchemy nicht möchte, dass ich die zugrunde liegende Abfrage kenne, da dies die allgemeine Natur der Schnittstelle der Ausdrucks-API in allen verschiedenen DB-APIs beeinträchtigt. Es macht mir nichts aus, wenn die Abfrage ausgeführt wird, bevor ich herausgefunden habe, was es war. Ich will nur wissen!
quelle
c = q.statement.compile(...)
, können Sie nur bekommenc.params
as_scalar()
-Methode vonQuery
.str(q)
.In der Dokumentation wird
literal_binds
eine Abfrageq
mit folgenden Parametern gedruckt :In der Dokumentation wird auch diese Warnung ausgegeben:
quelle
Dies sollte mit Sqlalchemy> = 0,6 funktionieren
quelle
adapt
auf diese Weise verwenden. Rufen Sie mindestens jedes Mal prep () für den Rückgabewert auf und geben Sie die Verbindung als Argument an, damit sie ordnungsgemäß in Anführungszeichen gesetzt werden kann.prepare
den Rückgabewert aufzurufen , aber es scheint, dass er diese Methode nicht hat :AttributeError: 'psycopg2._psycopg.AsIs' object has no attribute 'prepare'
. Ich benutze Psycopg2 2.2.1 BTWFür das MySQLdb-Backend habe ich Albertovs großartige Antwort (vielen Dank!) Ein wenig geändert. Ich bin sicher , sie könnten zusammengeführt werden zu überprüfen , ob
comp.positional
war ,True
aber das ist etwas über den Rahmen dieser Frage.quelle
return tuple(params)
wie ein Zauber zu funktionieren! Sie haben mir unzählige Stunden erspart, einen äußerst schmerzhaften Weg gehen zu müssen.Die Sache ist, dass sqlalchemy die Daten niemals mit Ihrer Abfrage mischt. Die Abfrage und die Daten werden separat an Ihren zugrunde liegenden Datenbanktreiber übergeben - die Interpolation der Daten erfolgt in Ihrer Datenbank.
Sqlalchemy übergibt die Abfrage, wie Sie sie gesehen haben,
str(myquery)
an die Datenbank, und die Werte werden in einem separaten Tupel gespeichert.Sie könnten einen Ansatz verwenden, bei dem Sie die Daten mit der Abfrage selbst interpolieren (wie unten von albertov vorgeschlagen), aber das ist nicht dasselbe, was sqlalchemy ausführt.
quelle
SELECT id WHERE date_added <= %s AND date_added >= %s ORDER BY count DESC
IST die letzte Abfrage. Diese%s
werden von sqlalchemy an die Datenbank gesendet - sqlalchemy setzt NIEMALS die tatsächlichen Daten anstelle von% ssqlalchemy.dialects.mysql.mysqldb
,do_executemany()
übergibt die Anweisung und die Parameter separat an den MySQLdb-Cursor. yay indirektion!Für das Postgresql-Backend mit psycopg2 können Sie auf das
do_execute
Ereignis warten und dann den Cursor, die Anweisung und den Typ erzwungene Parameter zusammen mit verwenden,Cursor.mogrify()
um die Parameter zu inline. Sie können True zurückgeben, um die tatsächliche Ausführung der Abfrage zu verhindern.Beispielnutzung:
quelle
Lassen Sie mich zunächst sagen, dass ich davon ausgehe, dass Sie dies hauptsächlich zu Debugging-Zwecken tun. Ich würde nicht empfehlen, die Anweisung außerhalb der fließenden SQLAlchemy-API zu ändern.
Leider scheint es keine einfache Möglichkeit zu geben, die kompilierte Anweisung mit den enthaltenen Abfrageparametern anzuzeigen. SQLAlchemy fügt die Parameter nicht in die Anweisung ein - sie werden als Wörterbuch an das Datenbankmodul übergeben . Auf diese Weise kann die datenbankspezifische Bibliothek beispielsweise das Escapezeichen von Sonderzeichen verarbeiten, um eine SQL-Injection zu vermeiden.
Sie können dies jedoch relativ einfach in zwei Schritten tun. Um die Anweisung zu erhalten, können Sie das tun, was Sie bereits gezeigt haben, und einfach die Abfrage ausdrucken:
Mit query.statement können Sie einen Schritt näher kommen, um die Parameternamen anzuzeigen. (Anmerkung
:id_1
unten vs%s
oben - in diesem sehr einfachen Beispiel kein wirkliches Problem, könnte aber der Schlüssel zu einer komplizierteren Aussage sein.)Anschließend können Sie die tatsächlichen Werte der Parameter abrufen, indem Sie die
params
Eigenschaft der kompilierten Anweisung abrufen:Dies funktionierte zumindest für ein MySQL-Backend. Ich würde erwarten, dass es auch allgemein genug für PostgreSQL ist, ohne es verwenden zu müssen
psycopg2
.quelle
Die folgende Lösung verwendet die SQLAlchemy Expression Language und funktioniert mit SQLAlchemy 1.1. Diese Lösung mischt die Parameter nicht mit der Abfrage (wie vom ursprünglichen Autor angefordert), bietet jedoch eine Möglichkeit, mithilfe von SQLAlchemy-Modellen SQL-Abfragezeichenfolgen und Parameterwörterbücher für verschiedene SQL-Dialekte zu generieren. Das Beispiel basiert auf dem Tutorial http://docs.sqlalchemy.org/en/rel_1_0/core/tutorial.html
Angesichts der Klasse,
Mit der Funktion select können wir eine Abfrageanweisung erstellen .
Als nächstes können wir die Anweisung in ein Abfrageobjekt kompilieren.
Standardmäßig wird die Anweisung mit einer grundlegenden 'Named'-Implementierung kompiliert, die mit SQL-Datenbanken wie SQLite und Oracle kompatibel ist. Wenn Sie einen Dialekt wie PostgreSQL angeben müssen, können Sie dies tun
Wenn Sie den Dialekt explizit als SQLite angeben möchten, können Sie den Parameterstil von "qmark" in "named" ändern.
Aus dem Abfrageobjekt können wir die Abfragezeichenfolge und die Abfrageparameter extrahieren
und führen Sie schließlich die Abfrage aus.
quelle
Sie können Ereignisse aus der ConnectionEvents- Familie verwenden:
after_cursor_execute
oderbefore_cursor_execute
.In sqlalchemy UsageRecipes von @zzzeek finden Sie dieses Beispiel:
Hier können Sie auf Ihre Abrechnung zugreifen
quelle
Als ich viele kleine Teile dieser verschiedenen Antworten zusammenstellte, kam ich auf das, was ich brauchte: einen einfachen Satz Code, den ich einlegen und gelegentlich, aber zuverlässig (dh alle Datentypen handhaben), um die genaue, kompilierte SQL zu erhalten, die an meine gesendet wurde Postgres-Backend durch einfaches Abfragen der Abfrage selbst:
quelle
Ich denke, .statement würde möglicherweise den Trick tun: http://docs.sqlalchemy.org/en/latest/orm/query.html?highlight=query
quelle