Взломать список для использования в 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.
(Существует вопрос связанный вопрос SO, но ответы, перечисленные там, либо не работают для MySQLDB, либо уязвимы для SQL-инъекции.)
Ответы
Ответ 1
Используйте 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, как параметр (не в тексте запроса), поэтому нет инъекции. Вы можете оставить любые символы, которые вы хотите в строке, не нужно удалять или указывать символы.
Ответ 2
Безболезненный 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)
Ответ 3
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)
Ответ 4
Как предложил этот человек (Выполнение "SELECT... WHERE... IN..." using MySQLdb), быстрее использовать itertools. repeat(), чтобы создать список "% s", чем умножить список ['% s'] (и намного быстрее, чем использование map()), особенно для длинных списков.
in_p = ', '.join(itertools.repeat('%s', len(args)))
Эти тайм-ауты были выполнены с использованием Python 2.7.3 с процессором Intel Core i5 M 540 @2.53GHz × 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
Ответ 5
Очень просто: просто используйте приведенную ниже формулу
rules_id = [ "9", "10" ]
sql1 = "SELECT * FROM attendance_rules_staff WHERE id in (" + ",".join(map (str, rules_id)) + ")"
",".join(map (str, rules_id))