在python MySQLDB IN子句中使用列表

时间:2009-02-26 05:59:26

标签: python mysql

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

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注入攻击。)

9 个答案:

答案 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.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

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.7pymysql==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))