10

使用 Python 的 DB API 规范,您可以将参数的参数传递给 execute() 方法。我的部分语句是 WHERE IN 子句,我一直在使用元组来填充 IN。例如:

params = ((3, 2, 1), )
stmt = "SELECT * FROM table WHERE id IN %s"
db.execute(stmt, params)

但是当我遇到参数元组只是一个元组的情况时,执行失败。

ProgrammingError:错误:“)”处或附近的语法错误第
13 行:ID 在哪里(3,)

如何让元组正确使用子句?

4

6 回答 6

13

编辑:如果您认为这个答案绕过了针对 SQL 注入攻击的内置保护,那么您就错了;仔细看。

使用pg8000(与 PostgreSQL 数据库引擎的 DB-API 2.0 兼容的 Pure-Python 接口)进行测试:

这是将多个参数传递给“IN”子句的推荐方法。

params = [3,2,1]
stmt = 'SELECT * FROM table WHERE id IN (%s)' % ','.join('%s' for i in params)
cursor.execute(stmt, params)

完整示例:

>>> from pg8000 import DBAPI
>>> conn = DBAPI.connect(user="a", database="d", host="localhost", password="p")
>>> c = conn.cursor()
>>> prms = [1,2,3]
>>> stmt = 'SELECT * FROM table WHERE id IN (%s)' % ','.join('%s' for i in prms)
>>> c.execute(stmt,prms)
>>> c.fetchall()
((1, u'myitem1'), (2, u'myitem2'), (3, u'myitem3'))
于 2010-02-12T17:48:51.230 回答
1

错误来自 3 之后的逗号。只需将其保留为单个值即可。

params = ((3), ... )
stmt = "SELECT * FROM table WHERE id IN %s"
db.execute(stmt, params)
于 2010-02-12T16:58:38.713 回答
1

这可能不是您所问问题的确切答案,但我认为它可能会解决您遇到的问题。

Python 的 DB-API 似乎没有为您提供将元组作为安全替换参数传递的方法。bernie 接受的答案是使用 Python%运算符进行替换,这是不安全的。

但是,您可能不必将元组作为参数传递,特别是当您想要的元组是另一个 SQL 查询的结果时(正如您向 Daniel 指出的那样)。相反,您可以使用 SQL 子查询。

如果您在 IN 子句中需要的一组 ID 是 的结果SELECT id FROM other_table WHERE use=true,例如:

stmt = "SELECT * FROM table WHERE id IN (SELECT id FROM other_table WHERE use=true)"
db.execute(stmt)

这也可以参数化(安全方式)。如果您要选择的 ID 是具有给定的 ID parent_id

stmt = "SELECT * FROM table WHERE id IN (SELECT id FROM other_table WHERE parent_id=%s)"
params = (parent_id,)
db.execute(stmt, params)
于 2016-08-16T22:07:36.420 回答
1

接受的答案有 SQL 注入的风险;您永远不应该将用户输入直接传递给数据库。相反,使用正确数量的占位符生成一个查询,然后让 pg8000 进行转义:

params = [3,2,1]
# SELECT * from table where id in (%s,%s,%s)
stmt = 'SELECT * FROM table WHERE id IN ({})'.format(','.join(['%s']*len(params)))
cursor.execute(stmt, tuple(params))
于 2017-04-07T19:15:04.700 回答
0

使用 f 字符串的解决方案。

params = [...]
stmt = f"SELECT * FROM table WHERE id IN ({','.join(['%s']*len(params ),)})"
db.execute(stmt, params)

如果还有另一个参数占位符,它将是这样的

age = 18
params = [...]
stmt = f"SELECT * FROM table WHERE age>%s AND id IN ({','.join(['%s']*len(params ),)})"
db.execute(stmt, tuple([age] + params))
于 2019-10-15T06:42:32.400 回答
0

正如问题所说,以下将失败:

params = ((3, 2, 1), )
stmt = "SELECT * FROM table WHERE id IN %s"
db.execute(stmt, params)

在 pg8000文档之后,IN可以用 an 替换ANY()以给出相同的结果:

params = ((3, 2, 1), )
stmt = "SELECT * FROM table WHERE id = ANY(%s)"
db.execute(stmt, params)

这会将查询和参数分别发送到服务器,避免 SQL 注入攻击。

于 2020-08-20T08:13:16.467 回答