Wie verwende ich Variablen in SQL-Anweisungen in Python?


91

Ok, ich bin nicht so erfahren in Python.

Ich habe den folgenden Python-Code:

cursor.execute("INSERT INTO table VALUES var1, var2, var3,")

Wo var1ist eine ganze Zahl, var2& var3sind Zeichenfolgen.

Wie kann ich die Variablennamen schreiben, ohne dass Python sie als Teil des Abfragetextes enthält?

Antworten:


103
cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3))

Beachten Sie, dass die Parameter als Tupel übergeben werden.

Die Datenbank-API führt das ordnungsgemäße Escape-Schreiben und Zitieren von Variablen durch. Achten Sie darauf, den Zeichenfolgenformatierungsoperator ( %) nicht zu verwenden , da

  1. es macht kein Entkommen oder Zitieren.
  2. Es ist anfällig für unkontrollierte Angriffe im String-Format, z . B. SQL-Injection .

Interessant, warum funktioniert es mit den Variablen separat anstatt in einem Array (var1, var2, var3)?
Andomar

Laut den DB-API-Spezifikationen kann es so oder so sein: python.org/dev/peps/pep-0249
Ayman Hourieh

9
@thekashyap Lesen Sie noch einmal sorgfältig. Unsicher ist die Verwendung des Zeichenfolgenformatierungsoperators %. Tatsächlich sage ich das in der Antwort.
Ayman Hourieh

Mein schlechtes .. Ich stellte mir ein % statt ,zwischen dem String und den Variablen vor .. kann mein Abstimmen aus verschiedenen Gründen nicht rückgängig machen .. Ich persönlich würde gerne Wörter wie unsicher / angreifen usw. sehen, die in der Beschreibung erwähnt werden, in der Sie don sagen 't use %..
Kashyap

1
@eric Die Antwort lautet: Verwenden Sie den % Operator nicht zum Formatieren der Zeichenfolge. Die %in der Zeichenfolge werden cursor.executedirekt von verwendet, und da es weiß, dass es SQL generiert, kann es mehr tun, um Sie zu schützen.
Mark Ransom

66

Verschiedene Implementierungen der Python DB-API dürfen unterschiedliche Platzhalter verwenden. Sie müssen also herausfinden, welchen Sie verwenden - dies könnte sein (z. B. mit MySQLdb):

cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3))

oder (zB mit sqlite3 aus der Python-Standardbibliothek):

cursor.execute("INSERT INTO table VALUES (?, ?, ?)", (var1, var2, var3))

oder noch andere (nachdem VALUESSie haben könnten (:1, :2, :3), oder "benannte Stile" (:fee, :fie, :fo)oder (%(fee)s, %(fie)s, %(fo)s)wo Sie ein Diktat anstelle einer Karte als zweites Argument übergeben execute). Überprüfen Sie die paramstyleZeichenfolgenkonstante in dem von Ihnen verwendeten DB-API-Modul und suchen Sie unter http://www.python.org/dev/peps/pep-0249/ nach paramstyle, um zu sehen, welche Stile zur Parameterübergabe vorhanden sind!


Ist es möglich, dasselbe zu tun, aber mit dem externen SQL-Skript?
Novitoll

46

Viele Möglichkeiten. Verwenden Sie NICHT das offensichtlichste ( %smit %) in echtem Code, es ist offen für Angriffe .

Hier kopieren und einfügen aus pydoc von sqlite3 :

# Never do this -- insecure!
symbol = 'RHAT'
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)

# Do this instead
t = ('RHAT',)
c.execute('SELECT * FROM stocks WHERE symbol=?', t)
print c.fetchone()

# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
             ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
             ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
            ]
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)

Weitere Beispiele, wenn Sie brauchen:

# Multiple values single statement/execution
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', ('RHAT', 'MSO'))
print c.fetchall()
c.execute('SELECT * FROM stocks WHERE symbol IN (?, ?)', ('RHAT', 'MSO'))
print c.fetchall()
# This also works, though ones above are better as a habit as it's inline with syntax of executemany().. but your choice.
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', 'RHAT', 'MSO')
print c.fetchall()
# Insert a single item
c.execute('INSERT INTO stocks VALUES (?,?,?,?,?)', ('2006-03-28', 'BUY', 'IBM', 1000, 45.00))

4
Einige der DB-API-Implementierungen verwenden tatsächlich% s für ihre Variablen - insbesondere psycopg2 für PostgreSQL. Dies ist nicht zu verwechseln (obwohl dies leicht möglich ist) mit der Verwendung von% s mit dem Operator% zum Ersetzen von Zeichenfolgen. Ich wäre wirklich nett, wenn wir aus Gründen der Portabilität nur eine definierte Standardmethode für die Angabe von SQL-Parametern für die DB-API haben könnten.
ThatAintWorking

23

http://www.amk.ca/python/writing/DB-API.html

Seien Sie vorsichtig, wenn Sie einfach Werte von Variablen an Ihre Anweisungen anhängen: Stellen Sie sich einen Benutzer vor, der sich selbst benennt. Aus ';DROP TABLE Users;'diesem Grund müssen Sie SQL Escape verwenden, das Python für Sie bereitstellt, wenn Sie cursor.execute auf anständige Weise verwenden. Beispiel in der URL ist:

cursor.execute("insert into Attendees values (?, ?, ?)", (name,
seminar, paid) )

13
Eigentlich ist es kein SQL-Escape. Es ist eine variable Bindung, die viel einfacher und direkter ist. Die Werte werden nach dem Parsen in die SQL-Anweisung eingebunden, sodass sie gegen jeden Injektionsangriff immun ist.
S.Lott

Ob es sich um SQL-Escapezeichen oder Variablenbindung handelt, hängt davon ab, wie gut oder schlecht Ihr Datenbankserver / DB-API-Treiber ist. Ich habe einige reale, weit verbreitete Produktionsdatenbanken gesehen, bei denen der DB-API-Treiber nur entkommen ist, anstatt Daten und Code außerhalb des Bandes zu halten. Unnötig zu erwähnen, dass ich diesen sogenannten "Datenbanken" nicht viel Respekt entgegenbringe.
Charles Duffy
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.