web-dev-qa-db-ja.com

SQLiteパラメーター置換問題

Python 2.5でSQLite3を使用して、リストを反復処理し、アイテムの名前に基づいてデータベースからアイテムの重みを取得しようとしています。

「?」を使ってみましたSQLインジェクションを防ぐためにパラメーターの置換が提案されましたが、機能しません。たとえば、私が使用する場合:

for item in self.inventory_names:
    self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", item)
    self.cursor.close()

エラーが表示されます:

sqlite3.ProgrammingError:指定されたバインディングの数が正しくありません。現在のステートメントでは1が使用され、8が指定されています。

これは何らかの形でデータベースの初期作成が原因であると考えています。実際にDBを作成するモジュールには、8つのバインディングがあります。

cursor.execute("""CREATE TABLE Equipment 
    (id INTEGER PRIMARY KEY, 
    name TEXT,
    price INTEGER, 
    weight REAL, 
    info TEXT, 
    ammo_cap INTEGER, 
    availability_west TEXT,
    availability_east TEXT)""")

ただし、各アイテム名に安全性の低い「%s」置換を使用すると、正常に機能します。そのようです:

for item in self.inventory_names:
    self.cursor.execute("SELECT weight FROM Equipment WHERE name = '%s'" % item)
    self.cursor.close()

1つだけを呼び出しているときに8つのバインドインを持っていると考える理由がわかりません。どうすれば修正できますか?

55
crystalattice

Cursor.execute()メソッドでは、2番目のパラメーターとしてシーケンスが必要です。たまたま8文字の文字列を指定しています。

代わりに次のフォームを使用してください。

self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", [item])

Pythonライブラリリファレンス:sqlite3 カーソルオブジェクト

128
ddaa

私はこのようなエラーが私に与える理由を理解しようとして半日を費やしました:

cursor.execute("SELECT * from ? WHERE name = ?", (table_name, name))

テーブル名を見つけるためだけにパラメータ化できません。これが他の人の時間の節約に役立つことを願っています。

55
ccpizz

データベースに挿入する必要がある値を表すcursor.executeの引数は、タプル(シーケンス)でなければなりません。ただし、この例を検討して、何が起こっているのかを確認してください。

>>> ('jason')
'jason'

>>> ('jason',)
('jason',)

最初の例は、代わりに文字列に評価されます。したがって、単一値のタプルを表す正しい方法は、2番目の評価の場合と同じです。とにかく、エラーを修正するための以下のコード。

self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", (item,))

また、cursor.execute値の引数を文字列として指定すると(これが実行されます)、例の最初の評価が行われ、エラーが発生します。

22
jgtumusiime

これを試してみましたか? :

for item in self.inventory_names:
    t = (item,)
    self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", t)
    self.cursor.close()

cursor.execute()では、2番目のパラメーターとしてシーケンス(リスト、タプル)が必要です。 (-> ddaa)

2
Blauohr

引用符(つまり、括弧はどういう意味ですか?)かっこで私のために働くようです。 (文字通り) '?'で試し続けましたしかし、私は取得し続けました

ProgrammingError:指定されたバインディングの数が正しくありません。現在のステートメントは0を使用し、1が指定されています。

私がやったとき:

ファクトイドからのファクトの選択WHEREキーLIKE(?)

の代わりに:

ファクトイドからファクトを選択しますWHEREキーLIKE '?'

動いた。

これはpython 2.6のことですか?

1
kjikaqawej

sqlite3 モジュールは、パラメータのtwo種類のプレースホルダーをサポートします。

qmarkスタイル

1つ以上の?を使用して各パラメーターの位置をマークし、パラメーターのリストまたはタプルを指定します。例えば。:

curs.execute("SELECT weight FROM Equipment WHERE name = ? AND price = ?",
             ['lead', 24])

名前付きスタイル

名前付きパラメーターごとに:parプレースホルダーを使用し、辞書を提供します。例えば。:

curs.execute("SELECT weight FROM Equipment WHERE name = :name AND price = :price",
             {name: 'lead', price: 24})

名前付きスタイルパラメータの利点は、パラメータの順序を気にする必要がなく、各:parが大規模/複雑なSQLクエリで複数回使用できることです。

0
Mike T

アイテムの各要素はタプルでなければなりません。名前は次のようになります:

names = ['Joe', 'Bob', 'Mary']

次のことを行う必要があります。

for item in self.inventory_names:
self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", (item, ))

(item、)を使用すると、文字列ではなくタプルになります。

0
Joey Nelson