“SELECT ... WHERE ... IN” 中参数数量不确定

14 投票
2 回答
10781 浏览
提问于 2025-04-17 16:52

我正在尝试进行一个查询,格式是...

SELECT col2 FROM tab WHERE col1 IN (val1, val2, val3...)

...其中的值存储在一个长度不固定的Python列表或元组中。我找不到一个“干净”的方法来做到这一点。

>>> db = connect(":memory:")
>>> db.execute("CREATE TABLE tab (col1 INTEGER, col2 TEXT)")
>>> db.execute("INSERT INTO tab VALUES(1,'one')")
>>> db.execute("INSERT INTO tab VALUES(2,'two')")
>>> db.execute("INSERT INTO tab VALUES(3,'three')")
>>> db.execute("INSERT INTO tab VALUES(4,'four')")
>>> db.execute("INSERT INTO tab VALUES(5,'five')")
>>> db.commit()

# Expected result
>>> db.execute("SELECT col2 FROM tab WHERE col1 IN (1,3,4)").fetchall()
[(u'one',), (u'three',), (u'four',)]

>>> vals = (1,3,4)

>>> db.execute("SELECT col2 FROM tab WHERE col1 IN (?)", vals).fetchall()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 1, and there are 3 supplied.

>>> db.execute("SELECT col2 FROM tab WHERE col1 IN (?)", (vals,)).fetchall()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type.

>>> db.execute("SELECT col2 FROM tab WHERE col1 IN (?)", (','.join(str(val) for val in vals),)).fetchall()
[]

>>> 

现在我可以这样做,我觉得这样做(如果我错了请纠正我)可以保持内置参数替换的安全性,但看起来还是有点丑:

>>> db.execute("SELECT col2 FROM tab WHERE col1 IN (" + ",".join("?"*len(vals)) + ")", vals).fetchall()
[(u'one',), (u'three',), (u'four',)]
>>> 

这是我最好的选择吗,还是有更好的方法呢?

2 个回答

1

一个简单明了的解决方案是:

vals = [1,3,4]
cursor.execute('SELECT col2 FROM tab WHERE col1 IN {}'.format(str(tuple(vals))
8

这是你在不使用额外库的情况下最好的选择。我之前确实多次推荐过这种方法,可以看看这里还有这里

你也可以考虑使用SQLAlchemy,它可以为你生成SQL语句,但这需要你花时间学习它,并且可能需要重写你大部分的应用程序。

撰写回答