2010-02-12 9 views
8

Con la especificación DB API de Python puede pasar un argumento de parámetros al método execute(). Parte de mi declaración es una cláusula WHERE IN y he estado usando una tupla para completar el IN. Por ejemplo:Pasando param a DB .execute para WHERE IN ... INT list

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

Pero cuando me encuentro con una situación en la tupla parámetro sólo es una tupla de 1 artículo, la ejecución falla.

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

¿Cómo puedo hacer que la tupla funcione correctamente con la cláusula?

Respuesta

8

Editar: Por favor, como menciona @rspeer en un comentario, tome precauciones para protegerse del ataque de inyección SQL.

Testing con pg8000 (a DB-API 2.0 compatible interfaz Pure-Python al motor de base de datos PostgreSQL):

Esta es la forma recomendada para pasar varios parámetros a una cláusula de "IN".

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

Otra edición (totalmente probado y ejemplo de trabajo):

>>> 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

Corrígeme si me equivoco, pero ¿su ejemplo no solo pasa el primer elemento solo a la subcláusula IN? > SELECCIONAR * FROM table WHERE id IN (3) –

+0

@John: tienes razón, gracias. Actualizando la respuesta con más información. – bernie

+1

Gracias, Adam. –

1

El error viene de la coma después de 3. Simplemente déjelo apagado para los valores individuales y listo.

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

Sí, sé por qué ocurrió el error, pero no estoy construyendo la tupla. La tupla está poblada por otro resultado de SQL. De paso, la tupla de un solo artículo conserva una coma colgante. –

+0

También quería señalar que una sola tupla de artículo debe tener una coma al final. –

+0

Ah, lo malentendí. Bueno, en ese caso podrías usar len() para obtener la longitud de la tupla y si es una, usar tuple [0] para extraer el valor sin la coma. – Daniel

1

Esto no puede ser una respuesta a exactamente la pregunta que usted pidió, pero creo que puede resolver el problema que tiene.

Python's DB-API no parece darle una forma de pasar tuplas como parámetros sustituidos con seguridad. La respuesta aceptada de bernie es usar el operador de Python % para la sustitución, que no es seguro.

Sin embargo, puede que no tenga que pasar tuplas como parámetros, particularmente cuando la tupla que desea es el resultado de otra consulta SQL (como le indicó a Daniel). En cambio, puede usar subconsultas de SQL.

Si el conjunto de ID que desea en su cláusula IN es el resultado de SELECT id FROM other_table WHERE use=true, por ejemplo:

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

Y esto se puede parametrizar (la manera segura), también. Si los ID que desea seleccionar son los que tienen un hecho 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 respuesta aceptada corre el riesgo de inyección de SQL; nunca debe pasar la entrada del usuario directamente a la base de datos. En su lugar, genere una consulta con el número correcto de marcadores de posición, luego deje que pg8000 escapa:

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

¿No es esto lo mismo que la respuesta aceptada? También está generando una consulta con el número correcto de marcadores de posición, no sustituyendo los parámetros directamente en la cadena de consulta. – BrenBarn

Cuestiones relacionadas