распаковка списка для использования в предложении 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 ответов:
использовать
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)