Come utilizzare le variabili nell'istruzione SQL in Python?


92

Ok, quindi non sono così esperto in Python.

Ho il seguente codice Python:

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

dove var1è un numero intero var2e var3sono stringhe.

Come posso scrivere i nomi delle variabili senza che Python li includa come parte del testo della query?

Risposte:


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

Notare che i parametri vengono passati come tupla.

L'API del database esegue correttamente l'escape e la quotazione delle variabili. Fare attenzione a non utilizzare l'operatore di formattazione della stringa ( %), perché

  1. non esegue alcuna fuga o citazione.
  2. è soggetto ad attacchi in formato stringa non controllato, ad esempio SQL injection .

Interessante, perché funziona con le variabili separatamente invece che in un array (var1, var2, var3)?
Andomar

Secondo le specifiche dell'API DB, sembra che possa essere in entrambi i casi: python.org/dev/peps/pep-0249
Ayman Hourieh

9
@thekashyap Leggi di nuovo attentamente. Quello che non è sicuro è usare l'operatore di formattazione della stringa %. In effetti, lo dico nella risposta.
Ayman Hourieh

colpa mia .. ho immaginato un % invece di ,tra la stringa e le variabili .. non posso annullare il mio voto negativo per vari motivi .. personalmente vorrei vedere parole come insicuro / attacco ecc. menzionate nella descrizione in cui dici don non usare %..
Kashyap

1
@eric la risposta dice di non utilizzare l' % operatore per formattare la stringa. Quelli %nella stringa vengono utilizzati cursor.executedirettamente e poiché sa che sta generando SQL, può fare di più per proteggerti.
Mark Ransom

68

Diverse implementazioni del Python DB-API possono utilizzare diversi segnaposto, quindi dovrai scoprire quale stai utilizzando - potrebbe essere (ad esempio con MySQLdb):

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

oppure (ad esempio con sqlite3 dalla libreria standard di Python):

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

o altri ancora (dopo VALUESche potresti avere (:1, :2, :3), o "stili con nome" (:fee, :fie, :fo)o (%(fee)s, %(fie)s, %(fo)s)dove passi un dict invece di una mappa come secondo argomento a execute). Controlla la paramstylecostante di stringa nel modulo API DB che stai utilizzando e cerca paramstyle su http://www.python.org/dev/peps/pep-0249/ per vedere quali sono tutti gli stili di passaggio dei parametri!


È possibile fare la stessa cosa ma con lo script SQL esterno?
Novitoll

47

Molti modi. NON usare quello più ovvio ( %scon %) nel codice reale, è aperto agli attacchi .

Qui copia-incolla da pydoc di 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)

Altri esempi se hai bisogno di:

# 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
Alcune delle implementazioni DB-API utilizzano effettivamente% s per le loro variabili, in particolare psycopg2 per PostgreSQL. Questo non deve essere confuso (sebbene lo sia facilmente) con l'uso di% s con l'operatore% per la sostituzione della stringa. Sarebbe davvero bello se, per la portabilità, potessimo avere solo un modo standard definito per specificare i parametri SQL per DB-API.
ThatAintWorking

25

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

Fai attenzione quando aggiungi semplicemente valori di variabili alle tue istruzioni: Immagina un utente che si nomina ';DROP TABLE Users;'- Ecco perché devi usare l'escaping sql, che Python ti fornisce quando usi il cursore.execute in modo decente. L'esempio nell'URL è:

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

13
In realtà, non è l'escape SQL. È un legame variabile, che è molto più semplice e diretto. I valori vengono associati all'istruzione SQL dopo l'analisi, rendendola immune a qualsiasi attacco di iniezione.
S.Lott

beh, se si tratta di escape SQL o di binding di variabili dipende da quanto è buono o cattivo il tuo server database / driver DB-API. Ho visto alcuni database di produzione del mondo reale e ampiamente distribuiti che hanno il loro driver DB-API semplicemente sfuggire, piuttosto che mantenere dati e codice fuori banda in rete. Inutile dire che non ho molto rispetto per quei cosiddetti "database".
Charles Duffy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.