Sé cómo asignar una lista a una cadena:
foostring = ",".join( map(str, list_of_ids) )
Y sé que puedo usar lo siguiente para incluir esa cadena en una cláusula IN:
cursor.execute("DELETE FROM foo.bar WHERE baz IN ('%s')" % (foostring))
Lo que necesito es lograr lo mismo de manera SEGURA (evitando la inyección de SQL) usando MySQLDB. En el ejemplo anterior, debido a que foostring no se pasa como argumento para ejecutar, es vulnerable. También tengo que citar y escapar fuera de la biblioteca mysql.
(Hay una pregunta SO relacionada , pero las respuestas enumeradas allí no funcionan para MySQLDB o son vulnerables a la inyección de SQL).
Respuestas:
Utilice
list_of_ids
directamente:format_strings = ','.join(['%s'] * len(list_of_ids)) cursor.execute("DELETE FROM foo.bar WHERE baz IN (%s)" % format_strings, tuple(list_of_ids))
De esa forma, evita tener que cotizar usted mismo y evita todo tipo de inyección SQL.
Tenga en cuenta que los datos (
list_of_ids
) van directamente al controlador de mysql, como un parámetro (no en el texto de la consulta) por lo que no hay inyección. Puede dejar los caracteres que desee en la cadena, sin necesidad de eliminarlos o citarlos.fuente
?
no es%s
así que funcionaría si cambia la primera línea aformat_strings = ','.join('?' * len(list_of_ids))
.% format_strings
parte cambie los otros%s
marcadores de posición en su consulta, solo elIN (%s)
marcador de posición: la forma de lograr esto es duplicar todos los%
caracteres excepto el que desea reemplazar:query = ("select distinct cln from vcf_commits where branch like %%s and repository like %%s and filename in (%s) and author not like %%s" % format_strings,); cursor.execute(query, (branch, repository) + tuple(fname_list) + (invalid_author,))
Aunque esta pregunta es bastante antigua, pensé que sería mejor dejar una respuesta en caso de que alguien más estuviera buscando lo que yo quería.
La respuesta aceptada se complica cuando tenemos muchos parámetros o si queremos usar parámetros con nombre
Después de algunas pruebas
ids = [5, 3, ...] # list of ids cursor.execute(''' SELECT ... WHERE id IN %(ids)s AND created_at > %(start_dt)s ''', { 'ids': tuple(ids), 'start_dt': '2019-10-31 00:00:00' })
Probado con
python2.7
,pymysql==0.7.11
fuente
Si usa
Django 2.0 or 2.1
yPython 3.6
, esta es la manera correcta:from django.db import connection RESULT_COLS = ['col1', 'col2', 'col3'] RESULT_COLS_STR = ', '.join(['a.'+'`'+i+'`' for i in RESULT_COLS]) QUERY_INDEX = RESULT_COLS[0] TABLE_NAME = 'test' search_value = ['ab', 'cd', 'ef'] # <-- a list query = ( f'SELECT DISTINCT {RESULT_COLS_STR} FROM {TABLE_NAME} a ' f'WHERE a.`{RESULT_COLS[0]}` IN %s ' f'ORDER BY a.`{RESULT_COLS[0]}`;' ) # <- 'SELECT DISTINCT a.`col1`, a.`col2`, a.`col3` FROM test a WHERE a.`col1` IN %s ORDER BY a.`col1`;' with connection.cursor() as cursor: cursor.execute(query, params=[search_value]) # params is a list with a list as its element
ref: https://stackoverflow.com/a/23891759/2803344 https://docs.djangoproject.com/en/2.1/topics/db/sql/#passing-parameters-into-raw
fuente
Aunque esta pregunta es bastante antigua. Estoy compartiendo mi solución si puede ayudar a alguien.
list_to_check = ['A', 'B'] cursor.execute("DELETE FROM foo.bar WHERE baz IN ({})".format(str(list_to_check)[1:-1])
Probado con
Python=3.6
fuente
list_to_check
no se escapa de SQL. Es por eso que pasar los valores como parámetros aexecute
es más apropiado. Utilice esta solución con mucho cuidado (es decir, los ID de entrada no se reciben como parámetros desde el exterior de su aplicación), ya que alguien podría usar esto para atacar su sistema y acceder a su base de datos.Otra solución simple que usa la comprensión de listas:
# creating a new list of strings and convert to tuple sql_list = tuple([ key.encode("UTF-8") for key in list_of_ids ]) # replace "{}" with "('id1','id2',...'idlast')" cursor.execute("DELETE FROM foo.bar WHERE baz IN {}".format(sql_list))
fuente
list_of_ids = [ 1, 2, 3] query = "select * from table where x in %s" % str(tuple(list_of_ids)) print query
Esto podría funcionar para algunos casos de uso si no desea preocuparse por el método en el que tiene que pasar argumentos para completar la cadena de consulta y desea invocar solo
cursror.execute(query)
.Otra forma podría ser:
"select * from table where x in (%s)" % ', '.join(str(id) for id in list_of_ids)
fuente
Muy simple: solo usa la siguiente formación
rules_id = ["9", "10"]
sql1 = "SELECCIONAR * DEL PERSONAL DE REGLAS DE ASISTENCIA DONDE id en (" + "," .join (map (str, id_reglas)) + ")"
"," .join (mapa (str, rules_id))
fuente
rules_id
contiene"); DROP TABLES Bobby --
?