web-dev-qa-db-ja.com

Python cx_Oracleバインド変数

私は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を使用しています。

13

バインディングを誤用しています。

できる限り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に感謝します。

37
ffarquet

@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

4
Tyler Christian