在Python MySQL IN子句中使用的列表的内拆

bn31dyow  于 2023-06-21  发布在  Mysql
关注(0)|答案(9)|浏览(98)

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

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

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

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

我需要的是使用MySQL数据库安全地完成同样的事情(避免SQL注入)。在上面的例子中,因为foostring没有作为参数传递给执行,所以它很容易受到攻击。我还必须引用并退出MySQL库。
(有一个related SO question,但那里列出的答案要么不适用于MySQL数据库,要么容易受到SQL注入的攻击。

np8igboo

np8igboo1#

直接使用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的驱动程序,因此没有注入。你可以在字符串中保留任何你想要的字符,不需要删除或引用字符。

e0uiprwp

e0uiprwp2#

虽然这个问题是相当老,认为这将是更好地留下回应的情况下,其他人正在寻找我想要的
当我们有很多参数或者我们想使用命名参数时,接受的答案会变得混乱
经过一些试验

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进行测试

vhipe2zx

vhipe2zx3#

这似乎仍然是Python3在2021年的问题,正如Rubms在评论markk的答案时指出的那样。
在mysql连接器包中的“www.example.com”中的方法“_process_params_dict”添加了大约9行代码cursor.py来处理元组,为我解决了这个问题:

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
sigwle7e

sigwle7e4#

也许这个问题有点晚了,但我偶然发现了一个类似的问题,但我想使用命名参数的dict而不是元组(因为如果我想修改参数来添加或删除一些,我不想重新构造元组,混乱的顺序可能非常容易,并导致bug...)。
我的解决方案是格式化查询字符串,将参数分解为几个参数,然后用这些新参数构造参数dict:

from typing import Iterable

query = """
SELECT *
FROM table
WHERE id IN (%(test_param)s)
"""

parameters = {"test_param": [1, 2, 3])

new_params = {}

for k, v in parameters.items():
    if isinstance(v, Iterable):
        iterable_params = {f"{k}_{i}": value for i, value in enumerate(v)}
        iterable_params_formatted = [f"%({k}_{i})s" for i in range(0, len(v))]
        query = query.replace(f"%({k})s", ", ".join(iterable_params_formatted))
        new_params.update(iterable_params)
    else:
        new_params[k] = v

print(query)
print(new_params)

结果:

> SELECT *
FROM table
WHERE id IN (%(test_param_0)s, %(test_param_1)s, %(test_param_2)s)

> {'test_param_0': 1, 'test_param_1': 2, 'test_param_2': 3}

可以做得更好,但我找不到使用命名参数的dict而不是有序元组的解决方案。

23c0lvtd

23c0lvtd5#

如果你使用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

参考:https://stackoverflow.com/a/23891759/2803344 https://docs.djangoproject.com/en/2.1/topics/db/sql/#passing-parameters-into-raw

bvuwiixz

bvuwiixz6#

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)
omjgkv6w

omjgkv6w7#

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

# 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))
piwo6bdm

piwo6bdm8#

虽然这个问题很古老。我分享我的解决方案,如果它可以帮助别人。
list_to_check = ['A', 'B'] cursor.execute("DELETE FROM foo.bar WHERE baz IN ({})".format(str(list_to_check)[1:-1])
使用Python=3.6进行测试

xdnvmnnf

xdnvmnnf9#

很简单:就用下面的队形
rules_id = [“9”,“10”]
“SELECT * FROM attendance_rules_staff WHERE id in(“+",“.join(map(str,rules_id))+”)”

",“.join(map(str,rules_id))

相关问题