101 votes

imploser une liste à utiliser dans une clause MySQLDB IN python

Je sais comment mapper une liste d'une chaîne de caractères:

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 d'accomplir la même chose en toute sécurité (éviter les injection SQL) à l'aide de MySQLDB. Dans l'exemple ci-dessus, car foostring est pas passé comme argument à exécuter, il est vulnérable. J'ai aussi de citer et de s'échapper à l'extérieur de la bibliothèque mysql.

(Il y a une relative DONC, la question, mais les réponses qui y sont énumérés, soit ne fonctionnent pas pour MySQLDB ou sont vulnérables à une injection SQL.)

186voto

nosklo Points 75862

Utilisez les 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, sans avoir besoin de supprimer ou de citer des caractères.

-1voto

Denis Ryzhkov Points 331

MySQLdb sans douleur execute('...WHERE name1 = %s AND name2 IN (%s)', value1, values2)

 def execute(sql, *values):

    assert sql.count('%s') == len(values), (sql, values)
    placeholders = []
    new_values = []
    for value in values:
        if isinstance(value, (list, tuple)):
            placeholders.append(', '.join(['%s'] * len(value)))
            new_values.extend(value)
        else:
            placeholders.append('%s')
            new_values.append(value)
    sql = sql % tuple(placeholders)
    values = tuple(new_values)

    # ... cursor.execute(sql, values)
 

-1voto

user2016290 Points 54

Comme cette personne a suggéré (Exécution "SELECT ... OÙ ... DANS ..." à l'aide de MySQLdb), il est plus rapide d'utiliser itertools.répéter() pour créer la liste des '%s que de multiplier les a ['%s'] liste (et beaucoup plus rapide que l'utilisation de la carte()), en particulier pour de longues listes.

in_p = ', '.join(itertools.repeat('%s', len(args)))

Ces timeits ont été effectuées à l'aide de Python 2.7.3 avec un processeur Intel Core i5 CPU M 540 @ 2.53 GHz × 4:

>>> timeit.timeit("repeat('%s', len(short_list))", 'from itertools import repeat; short_list = range(3)')
0.20310497283935547
>>> timeit.timeit("['%s'] * len(short_list)", 'short_list = range(3)')
0.263930082321167
>>> timeit.timeit("list(map(lambda x:'%s', short_list))", 'short_list = range(3)')
0.7543060779571533


>>> timeit.timeit("repeat('%s', len(long_list))", 'from itertools import repeat; long_list = range(1000)')
0.20342397689819336
>>> timeit.timeit("['%s'] * len(long_list)", 'long_list = range(1000)')
4.700995922088623
>>> timeit.timeit("list(map(lambda x:'%s', long_list))", 'long_list = range(1000)')
100.05319118499756

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X