Eu sei como mapear uma lista para uma string:
foostring = ",".join( map(str, list_of_ids) )
E eu sei que posso usar o seguinte para colocar essa string em uma cláusula IN:
cursor.execute("DELETE FROM foo.bar WHERE baz IN ('%s')" % (foostring))
O que eu preciso é realizar a mesma coisa com SEGURANÇA (evitando injeção de SQL) usando MySQLDB. No exemplo acima, porque foostring não é passado como um argumento a ser executado, ele é vulnerável. Eu também tenho que citar e escapar fora da biblioteca mysql.
(Há uma pergunta SO relacionada , mas as respostas listadas não funcionam para MySQLDB ou são vulneráveis à injeção de SQL.)
Respostas:
Use
list_of_ids
diretamente:format_strings = ','.join(['%s'] * len(list_of_ids)) cursor.execute("DELETE FROM foo.bar WHERE baz IN (%s)" % format_strings, tuple(list_of_ids))
Dessa forma, você evita ter que citar a si mesmo e evita todos os tipos de injeção de sql.
Observe que data (
list_of_ids
) está indo diretamente para o driver do mysql, como um parâmetro (não no texto da consulta), portanto, não há injeção. Você pode deixar qualquer caractere que desejar na string, sem necessidade de remover ou citar caracteres.fonte
?
não é,%s
então funcionaria se você alterasse a primeira linha paraformat_strings = ','.join('?' * len(list_of_ids))
.% format_strings
parte altere os outros%s
marcadores de posição em sua consulta, apenas oIN (%s)
marcador de posição - A maneira de fazer isso é dobrar todos os%
caracteres, exceto aquele que você deseja substituir: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,))
Embora esta questão seja bastante antiga, achei melhor deixar uma resposta caso outra pessoa estivesse procurando o que eu queria
A resposta aceita fica confusa quando temos muitos parâmetros ou se queremos usar parâmetros nomeados
Depois de algumas tentativas
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' })
Testado com
python2.7
,pymysql==0.7.11
fonte
Se você usa
Django 2.0 or 2.1
ePython 3.6
, este é o caminho certo: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
fonte
Embora esta questão seja bastante antiga. Estou compartilhando minha solução, se puder ajudar alguém.
list_to_check = ['A', 'B'] cursor.execute("DELETE FROM foo.bar WHERE baz IN ({})".format(str(list_to_check)[1:-1])
Testado com
Python=3.6
fonte
list_to_check
não está sendo escapado de SQL. É por isso que passar os valores como parâmetros paraexecute
é mais apropriado. Use esta solução com muito cuidado (ou seja, os IDs de entrada não são recebidos como parâmetros de fora de seu aplicativo), pois alguém poderia usar isso para atacar seu sistema e acessar seu banco de dados.Outra solução simples usando compreensão de lista:
# 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))
fonte
list_of_ids = [ 1, 2, 3] query = "select * from table where x in %s" % str(tuple(list_of_ids)) print query
Isso pode funcionar para alguns casos de uso, se você não quiser se preocupar com o método no qual deve passar argumentos para completar a string de consulta e gostaria de invocar apenas
cursror.execute(query)
.Outra forma poderia ser:
"select * from table where x in (%s)" % ', '.join(str(id) for id in list_of_ids)
fonte
Muito simples: basta usar a formação abaixo
regras_id = ["9", "10"]
sql1 = "SELECT * FROM assis_rules_staff WHERE id em (" + "," .join (map (str, rules_id)) + ")"
"," .join (map (str, rules_id))
fonte
rules_id
contém"); DROP TABLES Bobby --
?