imploding a list for use in a python MySQLDB IN clause

我知道如何将列表映射到字符串:

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

我知道我可以使用以下代码将字符串放入 IN 子句中:

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

我需要的是使用 MySQLDB 完成同样的事情 SAFELY (避免 SQL 注入)。在上面的示例中,由于 foostring 没有作为要执行的参数传递,因此它是脆弱的。我还必须在 mysql 库之外引用和转义。

(有一个 相关问题,但列出的答案要么不适用于 MySQLDB,要么容易受到 SQL 注入的影响。)

65984 次浏览

直接使用 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 注入。

Note that the data (list_of_ids) is going directly to mysql's driver, as a parameter (not in the query text) so there is no injection. You can leave any chars you want in the string, no need to remove or quote chars.

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)

Very simple: Just use the below formation

Rules _ id = [“9”,“10”]

Sql1 = “在(”+ “ ,”. join (map (str,rules _ id)) + “)”中的“ SELECT * FROM 饰 _ rules _ staff WHERE id”

”,“ . join (map (str,rules _ id))

如果你使用 Django 2.0 or 2.1Python 3.6,这是正确的方法:

from django.db import connection
RESULT_COLS = ['col1', 'col2', 'col3']
RESULT_COLS_STR = ', '.join(['a.'+'`'+i+'`' for i in RESULT_COLS])
QUERY_INDEX = RESULT_COLS[0]


TABLE_NAME = 'test'
search_value = ['ab', 'cd', 'ef']  # <-- a list
query = (
f'SELECT DISTINCT {RESULT_COLS_STR} FROM {TABLE_NAME} a '
f'WHERE a.`{RESULT_COLS[0]}` IN %s '
f'ORDER BY a.`{RESULT_COLS[0]}`;'
)  # <- 'SELECT DISTINCT a.`col1`, a.`col2`, a.`col3` FROM test a WHERE a.`col1` IN %s ORDER BY a.`col1`;'
with connection.cursor() as cursor:
cursor.execute(query, params=[search_value])  # params is a list with a list as its element

参考文献: < a href = “ https://stackoverflow. com/a/23891759/2803344”> https://stackoverflow.com/a/23891759/2803344 Https://docs.djangoproject.com/en/2.1/topics/db/sql/#passing-parameters-into-raw

虽然这个问题已经很老了,但是我认为最好还是留下一个回答,以防有人在寻找我想要的东西

当我们有很多参数或者我们想要使用命名参数时,接受的答案会变得很混乱

经过一些试验

ids = [5, 3, ...]  # list of ids
cursor.execute('''
SELECT
...
WHERE
id IN %(ids)s
AND created_at > %(start_dt)s
''', {
'ids': tuple(ids), 'start_dt': '2019-10-31 00:00:00'
})

python2.7pymysql==0.7.11测试

另一个使用列表内涵的简单解决方案:

# creating a new list of strings and convert to tuple
sql_list = tuple([ key.encode("UTF-8") for key in list_of_ids ])


# replace "{}" with "('id1','id2',...'idlast')"
cursor.execute("DELETE FROM foo.bar WHERE baz IN {}".format(sql_list))

尽管这个问题已经很老了,我还是分享一下我的解决方案,如果它能帮到别人的话。

List _ to _ check = [‘ A’,‘ B’] Execute (“ DELETE FROM foo.bar WHERE baz IN ({})”. format (str (list _ to _ check)[1:-1])

Python=3.6测试

正如 Rubms 在对 markk 的回答的评论中指出的那样,在2021年 Python 3似乎仍然存在这个问题。

将大约9行代码添加到 mysql 连接器包中“ cursor.py”中的“ _ process _ params _ dict”方法中以处理元组,为我解决了这个问题:

def _process_params_dict(self, params):
"""Process query parameters given as dictionary"""
try:
to_mysql = self._connection.converter.to_mysql
escape = self._connection.converter.escape
quote = self._connection.converter.quote
res = {}
for key, value in list(params.items()):
if type(value) is tuple: ### BEGIN MY ADDITIONS
res[key.encode()] = b''
for subvalue in value:
conv = subvalue
conv = to_mysql(conv)
conv = escape(conv)
conv = quote(conv)
res[key.encode()] = res[key.encode()] + b',' + conv if len(res[key.encode()]) else conv
else: ### END MY ADDITIONS
conv = value
conv = to_mysql(conv)
conv = escape(conv)
conv = quote(conv)
res[key.encode()] = conv
except Exception as err:
raise errors.ProgrammingError(
"Failed processing pyformat-parameters; %s" % err)
else:
return res