imploding在python MySQLDB IN子句中使用的列表

我知道如何将一个列表映射到一个string:

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

而且我知道我可以使用以下命令将该string转换为IN子句:

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

我需要的是用MySQLDB安全地完成同样的事情(避免SQL注入)。 在上面的例子中,因为foostring没有被作为parameter passing来执行,所以它很脆弱。 我也必须引用和逃避外部的MySQL库。

(这里有一个相关的SO问题 ,但是那里列出的答案要么不适用于MySQLDB,要么很容易被SQL注入。

直接使用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的驱动程序,作为参数(不在查询文本中),所以没有注入。 你可以留下string中的任何字符,不需要删除或引用字符。

无痛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) 
 list_of_ids = [ 1, 2, 3] query = "select * from table where x in %s" % str(tuple(list_of_ids)) print query 

如果您不希望关注要传递参数来完成查询string的方法,而只想调用cursror.execute(query) ,那么这可能适用于某些用例。

另一种方式可能是:

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

正如这个人所build议的那样( 使用MySQLdb执行“SELECT … WHERE … IN …” ),使用itertools.repeat()创build'%s'的列表要比乘以['%s ']列表(并比使用map()快得多,特别是对于长列表。

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

这些时间是使用Python 2.7.3与英特尔酷睿i5 CPU 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