2010-02-12 10 views
8

Con le specifiche API DB di Python è possibile passare un argomento di parametri al metodo execute(). Parte della mia affermazione è una clausola WHERE IN e ho usato una tupla per popolare l'IN. Per esempio:Passare param a DB .execute per WHERE IN ... INT lista

params = ((3, 2, 1),) 
stmt = "SELECT * FROM table WHERE id IN %s" 
db.execute(stmt, params) 

Ma quando mi imbatto in una situazione in cui il parametro tupla è solo una tupla di 1 articolo, l'esecuzione non riesce.

ProgrammingError: ERROR: syntax error at or near ")"
LINE 13: WHERE id IN (3,)

Come posso far funzionare correttamente la tupla con la clausola?

risposta

8

Modifica: Per favore, come @speer menziona in un commento, prendere precauzioni per proteggersi dall'attacco di SQL injection.

Test con pg8000 (un DB-API 2.0 compatibile con l'interfaccia Pure-Python per il motore di database PostgreSQL):

Questo è il metodo consigliato per passare più parametri a una clausola "IN".

params = [3,2,1] 
stmt = 'SELECT * FROM table WHERE id IN (%s)' % ','.join('%s' for i in params) 
cursor.execute(stmt, params) 

Un'altra modifica (completamente testato e l'esempio di lavoro):

>>> from pg8000 import DBAPI 
>>> conn = DBAPI.connect(user="a", database="d", host="localhost", password="p") 
>>> c = conn.cursor() 
>>> prms = [1,2,3] 
>>> stmt = 'SELECT * FROM table WHERE id IN (%s)' % ','.join('%s' for i in prms) 
>>> c.execute(stmt,prms) 
>>> c.fetchall() 
((1, u'myitem1'), (2, u'myitem2'), (3, u'myitem3')) 
+1

Correggetemi se ho torto, ma il tuo esempio non passa solo il primo elemento solo alla sotto-clausola IN? > SELECT * FROM table WHERE id IN (3) –

+0

@John: hai ragione, grazie. Aggiornamento della risposta con maggiori informazioni. – bernie

+1

Grazie, Adam. –

1

L'errore viene dalla virgola dopo il 3. Basta lasciarlo spento per i singoli valori e si è impostato.

params = ((3), ...) 
stmt = "SELECT * FROM table WHERE id IN %s" 
db.execute(stmt, params) 
+0

Si lo so il motivo per cui l'errore è accaduto, ma io non sto costruendo la tupla. La tupla è popolata da un altro risultato SQL. Quindi, di passaggio, la tupla di un singolo elemento mantiene una virgola sospesa. –

+0

Volevo anche sottolineare che una tupla di un singolo elemento deve avere una virgola finale. –

+0

Ah, ho frainteso. Bene, in quel caso potresti usare len() per ottenere la lunghezza della tupla e se la sua usa la tupla [0] per estrarre il valore senza la virgola. – Daniel

1

questo non può essere una risposta al esattamente la domanda che hai posto, ma penso che potrebbe risolvere il problema che avete.

La DB-API di Python non sembra fornire un modo per passare le tuple come parametri sostituiti in modo sicuro. La risposta accettata da bernie sta utilizzando l'operatore Python % per la sostituzione, che non è sicuro.

Tuttavia, potrebbe non essere necessario passare le tuple come parametri, in particolare quando la tupla desiderata è il risultato di un'altra query SQL (come indicato da Daniel). Invece, è possibile utilizzare sottoquery SQL.

Se l'insieme di ID che volete nella vostra clausola IN è il risultato di SELECT id FROM other_table WHERE use=true, ad esempio:

stmt = "SELECT * FROM table WHERE id IN (SELECT id FROM other_table WHERE use=true)" 
db.execute(stmt) 

E questo può essere parametrizzata (il modo sicuro), anche. Se gli ID che si desidera selezionare sono quelli con un dato parent_id:

stmt = "SELECT * FROM table WHERE id IN (SELECT id FROM other_table WHERE parent_id=%s)" 
params = (parent_id,) 
db.execute(stmt, params) 
0

La risposta accettata rischi di SQL injection; non si dovrebbe mai passare l'input dell'utente direttamente al database. Invece, generare una query con il numero corretto di segnaposto, poi lasciare pg8000 fanno la fuga:

params = [3,2,1] 
# SELECT * from table where id in (%s,%s,%s) 
stmt = 'SELECT * FROM table WHERE id IN ({})'.format(','.join(['%s']*len(params))) 
cursor.execute(stmt, tuple(params)) 
+0

Non è la stessa cosa la risposta accettata? Sta anche generando una query con il giusto numero di segnaposti, non sostituendo i parametri direttamente nella stringa di query. – BrenBarn

Problemi correlati