我知道如何将列表映射到字符串:
foostring = ",".join( map(str, list_of_ids) )
我知道我可以使用以下内容将该字符串转换为IN子句:
cursor.execute("DELETE FROM foo.bar WHERE baz IN ('%s')" % (foostring))
我需要的是使用MySQLDB安全地完成同样的事情(避免SQL注入)。在上面的示例中,因为foostring不作为参数传递来执行,所以它很容易受到攻击。我还必须在mysql库之外引用并转义。
(有related SO question,但其中列出的答案要么不适用于MySQLDB,要么易受SQL注入攻击。)
答案 0 :(得分:122)
直接使用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的驱动程序,因此没有注入。你可以在字符串中留下你想要的任何字符,不需要删除或引用字符。
答案 1 :(得分:0)
如果您使用Django 2.0 or 2.1
和Python 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
ref:https://stackoverflow.com/a/23891759/2803344 https://docs.djangoproject.com/en/2.1/topics/db/sql/#passing-parameters-into-raw
答案 2 :(得分:0)
尽管这个问题已经很久了,以为最好在别人找我想要的东西时留下答案
当我们有很多参数或想要使用命名参数时,可接受的答案会变得混乱
经过一些试验
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.7
,pymysql==0.7.11
答案 3 :(得分:0)
使用列表推导的另一种简单解决方案:
# 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))
答案 4 :(得分:0)
这似乎仍然是 2021 年 Python3 的一个问题,正如 Rubms 在对 markk 的回答的评论中所指出的那样。
在mysql连接器包中“cursor.py”中的方法“_process_params_dict”中添加约9行代码来处理元组,解决了我的问题:
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
答案 5 :(得分:-1)
无痛的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)
答案 6 :(得分:-2)
尽管这个问题已经很久了。我正在分享我的解决方案,如果它可以帮助某人。
list_to_check = ['A', 'B']
cursor.execute("DELETE FROM foo.bar WHERE baz IN ({})".format(str(list_to_check)[1:-1])
经过Python=3.6
答案 7 :(得分:-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)
答案 8 :(得分:-5)
非常简单:只需使用以下格式
rules_id = [&#34; 9&#34;,&#34; 10&#34;]
sql1 =&#34; SELECT * FROM attendance_rules_staff WHERE id in(&#34; +&#34;,&#34; .join(map(str,rules_id))+&#34;)&#34 ;
&#34;,&#34; .join(map(str,rules_id))