SQLite“IN”子句的参数替换

新手上路,请多包涵

我正在尝试 在 Python 中对 IN 子句使用 SQLite 的 参数替换。这是一个完整的运行示例,用于演示:

 import sqlite3

c = sqlite3.connect(":memory:")
c.execute('CREATE TABLE distro (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)')

for name in 'Ubuntu Fedora Puppy DSL SuSE'.split():
  c.execute('INSERT INTO distro (name) VALUES (?)', [ name ] )

desired_ids = ["1", "2", "5", "47"]
result_set = c.execute('SELECT * FROM distro WHERE id IN (%s)' % (", ".join(desired_ids)), ())
for result in result_set:
  print result

它打印出来:

(1、u’Ubuntu’) (2、u’Fedora’) (5、u’SuSE’)

正如文档所述“[y] 你不应该使用 Python 的字符串操作来组合你的查询,因为这样做是不安全的;它使你的程序容易受到 SQL 注入攻击,”我希望使用参数替换。

当我尝试时:

 result_set = c.execute('SELECT * FROM distro WHERE id IN (?)', [ (", ".join(desired_ids)) ])

我得到一个空的结果集,当我尝试时:

 result_set = c.execute('SELECT * FROM distro WHERE id IN (?)', [ desired_ids ] )

我得到:

InterfaceError:错误绑定参数 0 - 可能是不支持的类型。

虽然我希望这个简化问题的任何答案都能奏效,但我想指出我要执行的实际查询是在双重嵌套子查询中。以机智:

 UPDATE dir_x_user SET user_revision = user_attempted_revision
WHERE user_id IN
    (SELECT user_id FROM
        (SELECT user_id, MAX(revision) FROM users WHERE obfuscated_name IN
            ("Argl883", "Manf496", "Mook657") GROUP BY user_id
        )
    )

原文由 Clinton Blackmore 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 597
2 个回答

您确实需要正确数量的 ? s,但这不会带来 sql 注入风险:

 >>> result_set = c.execute('SELECT * FROM distro WHERE id IN (%s)' %
                           ','.join('?'*len(desired_ids)), desired_ids)
>>> print result_set.fetchall()
[(1, u'Ubuntu'), (2, u'Fedora'), (5, u'SuSE')]

原文由 Alex Martelli 发布,翻译遵循 CC BY-SA 2.5 许可协议

根据 http://www.sqlite.org/limits.html (第 9 项),SQLite 无法(默认情况下)处理超过 999 个参数的查询,因此此处的解决方案(生成所需的占位符列表)将如果您正在寻找数千个项目,则会失败 IN 。如果是这种情况,您将需要分解列表然后遍历它的各个部分并自己加入结果。

如果您的 IN 子句中不需要数千个项目,那么 Alex 的解决方案就是这样做的方式(并且似乎是 Django 的方式)。

原文由 cibyr 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏