私はPython初心者です。バインド変数の使用に問題があります。以下のコードを実行すると、すべて正常に動作します。
bind= {"var" : "ciao"}
sql = "select * from sometable where somefield = :bind"
cur.prepare(sql)
cur.execute(sql,bind)
代わりに、別のバインド変数を追加すると、エラーが発生します。
bind= {"var" : "ciao"}
sql = "select * from sometable where somefield = :bind and otherfield = :bind"
cur.prepare(sql)
cur.execute(sql,(bind,bind))
cur.execute(sql,(bind,bind))
Oracle.NotSupportedError: Variable_TypeByValue(): unhandled data
私はそれを解決しました
cur.execute(sql,(bind["var"],bind["var"]))
しかし、前のコマンドがうまくいかなかった理由を理解できません。
バインド変数を使用する正しい方法はどれですか? cx_Oracleを使用しています。
バインディングを誤用しています。
できる限りcx_Oracleで変数をバインドする3つの異なる方法があります こちらを参照 :
1)Tupleをnumbered variablesでSQLステートメントに渡すことにより:
sql = "select * from sometable where somefield = :1 and otherfield = :2"
cur.execute(sql, (aValue, anotherValue))
2)キーワード引数をSQLステートメントに渡すwith named variables:
sql = "select * from sometable where somefield = :my_field and otherfield = :anotherOne"
cur.execute(sql, myField=aValue, anotherOne=anotherValue)
3)ディクショナリをSQLステートメントに渡すことによってwith named variables:
sql = "select * from sometable where somefield = :my_field and otherfield = :anotherOne"
cur.execute(sql, {"myField":aValue, "anotherOne":anotherValue})
なぜコードが機能するのか?
ここで何が起こるかを理解してみましょう:
bind= {"var" : "ciao"}
sql = "select * from sometable where somefield = :bind and otherfield = :bind"
cur.execute(sql,(bind["var"], bind["var"]))
Oracleは、1つの変数が必要であることを理解します。これは名前付き変数で、bind
という名前でリンクされています。次に、次のような名前付きパラメーターとしてパラメーターを指定する必要があります。
cur.execute(sql, bind="ciao")
または、そのような辞書を使用して:
cur.execute(sql, {bind:"ciao"})
ただし、cx_Oracleは代わりにTupleを受け取るので、SQLステートメントが次のように番号でバインディングでフォールバックします。
sql = "select * from sometable where somefield = :1 and otherfield = :2"
そして、bind['var']
を2回、これは文字列"ciao"
。 2つのTupleアイテムを番号付き変数にマッピングしています:
cur.execute(sql, ("ciao", "ciao"))
それは偶然に実行されますが、コードは非常に誤解を招きます。
バインドする単一の値を持つタプル
また、最初のオプションにはタプルが必要です。しかし、バインドする単一の値がある場合、この表記法を使用して単一の値のタプルを作成できます。
sql = "select * from sometable where somefield = :1"
cur.execute(sql, (aValue,))
[編集]:dictを渡すことがcx_Oracleによってサポートされていることを言及してくれた@ tyler-christianに感謝します。
@ffarquestによると、辞書の使用はcx_Oracleではサポートされていませんが、実際には@ giovanni-de-ciantisが辞書を誤って使用しているだけです。
named_params = {'dept_id':50, 'sal':1000}
query1 = cursor.execute(
'SELECT * FROM employees WHERE department_id=:dept_id AND salary>:sal',
named_params
)
OR
query2 = cursor.execute(
'SELECT * FROM employees WHERE department_id=:dept_id AND salary>:sal',
dept_id=50,
sal=1000
)
与えられた例では、:bind
への2番目の参照は、順番に行われていないため、別のものに置き換える必要があると思います。また、混乱を取り除くために変数bind
の名前を変更しました。
bind_dict = {bind:"var" : diff:"ciao"}
sql = "select * from sometable where somefield=:bind and otherfield=:diff"
cur.prepare(sql)
cur.execute(sql, bind_dict )
この記事は、辞書を使用できることを示す2007年の記事です。 http://www.Oracle.com/technetwork/articles/dsl/prez-python-queries-101587.html