распаковка списка для использования в предложении python MySQLDB IN


Я знаю, как сопоставить список в строку:

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

и я знаю, что я могу использовать следующее, Чтобы получить эту строку в предложение IN:

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

что мне нужно, это сделать то же самое безопасно (избегая SQL-инъекции) с помощью MySQLDB. В приведенном выше примере, поскольку foostring не передается в качестве аргумента для выполнения, он уязвим. Я также должен цитировать и бежать за пределы библиотеки mysql.

(есть связанный с этим вопрос, но ответы, перечисленные там, либо не работают для MySQLDB, либо уязвимы для SQL-инъекции.)

5 55

5 ответов:

использовать list_of_ids напрямую:

format_strings = ','.join(['%s'] * len(list_of_ids))
cursor.execute("DELETE FROM foo.bar WHERE baz IN (%s)" % format_strings,
                tuple(list_of_ids))

таким образом, вы избегаете необходимости цитировать себя и избегать всех видов SQL-инъекций.

обратите внимание, что данные (list_of_ids) идет непосредственно к драйверу mysql, как параметр (не в тексте запроса), поэтому нет инъекции. Вы можете оставить любые символы, которые вы хотите в строке, не нужно удалять или цитировать символы.

без боли MySQLdb 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)

как этот человек предложил (выполнение " SELECT ... ГДЕ... В..."с помощью MySQLdb), это быстрее использовать itertools.повторите (), чтобы создать список "%s", чем умножить список ["%s"] (и гораздо быстрее, чем с помощью map ()), особенно для длинных списков.

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

эти timeits были сделаны с использованием Python 2.7.3 с процессором Intel Core i5 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
list_of_ids = [ 1, 2, 3]
query = "select * from table where x in %s" % str(tuple(list_of_ids))
print query

Это может работать для некоторых случаев использования, если вы не хотите иметь дело с методом, в котором вы должны передать аргументы для завершения строки запроса и хотели бы вызвать только cursror.execute(query).

другой способ может быть:

"select * from table where x in (%s)" % ', '.join(str(id) for id in list_of_ids)

очень просто: просто используйте ниже формирование

rules_id = ["9","10"]

sql1 = " SELECT * FROM attendance_rules_staff WHERE id in ("+",".присоединиться(карта(ул. rules_id))+")"

",".присоединиться(карта(ул. rules_id))