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?

user111606
quelle

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 .
Ayman Hourieh
quelle
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!

Alex Martelli
quelle
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))
Kashyap
quelle
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) )
Num Lock
quelle
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