内联列表以在python MySQLDB IN子句中使用


84

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

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

而且我知道我可以使用以下命令将该字符串放入IN子句中:

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

我需要使用MySQLDB安全地完成同一件事(避免SQL注入)。在上面的示例中,由于foostring没有作为执行参数传递,因此它很容易受到攻击。我还必须在mysql库之外引用和转义。

(有一个相关的SO问题,但是那里列出的答案对MySQLDB不起作用或容易受到SQL注入的影响。)


您也许能够从在PHP做了一个类似的问题得到一些启示stackoverflow.com/questions/327274/...
Zoredache


@mluebke关于在查询中传递多个列表的任何想法吗?
Dipen Dedania

Answers:


157

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的驱动程序(不在查询文本中),因此没有注入。您可以在字符串中保留任何想要的字符,而无需删除或引用字符。


2
@heikogerlach:我没有引用%s ...第一行创建了一个字符串“%s,%s,%s” ...的长度与list_of_ids长度相同。
nosklo

啊,你是对的。需要更加努力。我莫名其妙地把它混合了。不错的解决方案。

在sqlite中也可以使用吗?因为我刚尝试过,它似乎指出了语法错误。
Sohaib 2014年

在sqlite中的@Sohaib替换字符?不是,%s所以如果将第一行更改为,它将起作用format_strings = ','.join('?' * len(list_of_ids))
2014年

1
@kdas在您的情况下,您不希望该% format_strings部分更改%s查询中的其他占位符,仅更改占位IN (%s)符-实现此目的的方法是将所有%字符加倍(除了要替换的字符):query = ("select distinct cln from vcf_commits where branch like %%s and repository like %%s and filename in (%s) and author not like %%s" % format_strings,); cursor.execute(query, (branch, repository) + tuple(fname_list) + (invalid_author,))
nosklo

5

尽管这个问题已经很久了,但最好还是留下一个答案,以防其他人在寻找我想要的东西

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

经过一番试验

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


2
这不适用于python 3和mysql-connector-python 8.0.21。返回错误“ Python元组不能转换为MySQL类型”。
鲁姆斯

-1

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


-1

虽然这个问题已经很老了。我正在分享我的解决方案,如果它可以帮助某人。

list_to_check = ['A', 'B'] cursor.execute("DELETE FROM foo.bar WHERE baz IN ({})".format(str(list_to_check)[1:-1])

经过测试 Python=3.6


恐怕此解决方案容易受到SQL注入攻击的攻击,因为所提供的list_to_check内容并未经过SQL转义。这就是将值作为参数传递给execute更合适的原因。请谨慎使用此解决方案(即,不会从应用程序外部将输入ID作为参数接收),因为有人可能会使用此解决方案攻击您的系统并访问您的数据库。
鲁姆斯

-2

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

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

如果您不希望使用必须传递参数以完成查询字符串的方法,并且希望调用just的方法,则这在某些用例中可能会起作用cursror.execute(query)

另一种方法可能是:

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

-7

很简单:只需使用以下格式

rules_id = [“ 9”,“ 10”]

sql1 =“ SELECT * FROM Attenance_rules_staff WHERE id in(” +“,” .join(map(str,rules_id))+“)”

“,”。join(map(str,rules_id))


它在哪里执行sql引用,这不是使用文字而不是绑定变量吗?
eckes

不需要,它只是工作正常。您可以测试因为元组结构直接用第一个大括号(“ 9”,“ 10”)转换为字符串。哪个调整sql格式。因此,您不需要其他形式即可使SQL可调整
Rahman

1
并且如果rules_id包含"); DROP TABLES Bobby --
eckes

已经告诉“内嵌列表”而不是“)... ...所以在查询之前,您需要验证
Mizanur Ra​​hman

或使用:sql1 =“ SELECT * FROM Attenance_rules_staff WHERE id in(” +“,” .join(map(str(ru,rules_id))+“)”)
Mizanur Ra​​hman
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.