web-dev-qa-db-fra.com

imploser une liste à utiliser dans une clause MySQLDB IN python

Je sais comment mapper une liste sur une chaîne:

foostring = ",".join( map(str, list_of_ids) )

Et je sais que je peux utiliser ce qui suit pour obtenir cette chaîne dans une clause IN:

cursor.execute("DELETE FROM foo.bar WHERE baz IN ('%s')" % (foostring))

Ce dont j'ai besoin, c'est de faire la même chose en toute sécurité (en évitant l'injection de SQL) avec MySQLDB. Dans l'exemple ci-dessus, parce que foostring n'est pas transmis en tant qu'argument à exécuter, il est vulnérable. Je dois aussi citer et m'échapper en dehors de la bibliothèque mysql. 

(Il y a une question liée à SO , mais les réponses répertoriées ici ne fonctionnent pas pour MySQLDB ou sont vulnérables à l'injection SQL.)

61
mluebke

Utilisez le list_of_ids directement:

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 cette façon, vous évitez de vous citer vous-même et évitez toutes sortes d’injections SQL.

Notez que les données (list_of_ids) vont directement au pilote de mysql, en tant que paramètre (pas dans le texte de la requête), il n'y a donc pas d'injection. Vous pouvez laisser les caractères de votre choix dans la chaîne, vous n'avez pas besoin de supprimer ou de citer des caractères.

116
nosklo

Si vous utilisez Django 2.0 or 2.1 et Python 3.6, voici le bon moyen:

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/2803344https://docs.djangoproject.com/fr/2.1/topics/db/sql/#passing-parameters-into-raw

0
Belter