14

次の形式でクエリを実行しようとしています...

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',)]
>>> 

それが私の最善の選択肢ですか、それともこれを回避するより良い方法はありますか?

4

2 に答える 2

8

これは、追加のライブラリを使用しない最適なオプションです。私は確かに過去にそのテクニックを提唱してきました。実際には一度ならず。

また、SQL を生成する SQLAlchemy を使用するように切り替えることもできますが、その場合、学習曲線を上ってアプリケーションの大部分を書き直す必要があります。

于 2013-02-23T14:25:51.313 に答える