web-dev-qa-db-fra.com

Python variables de liaison cx_Oracle

Je suis un Python, j'ai des problèmes dans l'utilisation des variables de liaison. Si j'exécute le code ci-dessous, tout fonctionne bien.

bind= {"var" : "ciao"}
sql = "select * from sometable where somefield = :bind"
cur.prepare(sql)
cur.execute(sql,bind)

Au lieu de cela, si j'ajoute une autre variable de liaison, j'obtiens une erreur.

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

Je l'ai résolu avec

cur.execute(sql,(bind["var"],bind["var"]))

mais je ne comprends pas pourquoi la commande précédente n'était pas correcte.

Quelle est la bonne façon d'utiliser les variables de liaison? J'utilise cx_Oracle.

13
Giovanni De Ciantis

Vous abusez de la liaison.

Il existe trois façons différentes de lier des variables avec cx_Oracle comme on peut voir ici :

1) en passant un Tuple à une instruction SQL avec variables numérotées :

sql = "select * from sometable where somefield = :1 and otherfield = :2"
cur.execute(sql, (aValue, anotherValue))

2) En passant des arguments de mots clés à une instruction SQL avec des variables nommées :

sql = "select * from sometable where somefield = :my_field and otherfield = :anotherOne"
cur.execute(sql, myField=aValue, anotherOne=anotherValue)

3) En passant un dictionnaire à une instruction SQL avec des variables nommées :

sql = "select * from sometable where somefield = :my_field and otherfield = :anotherOne"
cur.execute(sql, {"myField":aValue, "anotherOne":anotherValue})

Remarques

Pourquoi votre code fonctionne-t-il alors?

Essayons de comprendre ce qui se passe ici:

bind= {"var" : "ciao"}
sql = "select * from sometable where somefield = :bind and otherfield = :bind"
cur.execute(sql,(bind["var"], bind["var"]))

Oracle comprendra qu'il attend une variable. Il s'agit d'une variable nommée, liée par le nom bind. Vous devez ensuite donner un paramètre en tant que paramètre nommé comme ceci:

cur.execute(sql, bind="ciao")

Ou en utilisant un dictionnaire, comme ça:

cur.execute(sql, {bind:"ciao"})

Cependant, comme cx_Oracle reçoit un Tuple à la place, il se replie dans une liaison par numéro, comme si votre instruction SQL était:

sql = "select * from sometable where somefield = :1 and otherfield = :2"

Et pendant que vous passez bind['var'] deux fois, qui est juste la chaîne "ciao". Il associe les deux éléments Tuple aux variables numérotées:

cur.execute(sql, ("ciao", "ciao"))

Cela fonctionne par hasard mais le code est très trompeur.

Tuple avec une seule valeur à lier

Notez également que la première option nécessite un tuple. Mais si vous avez une seule valeur à lier, vous pouvez utiliser cette notation pour créer un Tuple d'une seule valeur:

sql = "select * from sometable where somefield = :1"
cur.execute(sql, (aValue,))

[EDIT]: Merci à @ tyler-christian d'avoir mentionné que la passation d'un dict était prise en charge par cx_Oracle.

37
ffarquet

@ffarquest dit que l'utilisation d'un dictionnaire n'est pas prise en charge par cx_Oracle mais c'est en fait que @ giovanni-de-ciantis ne l'utilisait pas correctement.


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
)

Dans l'exemple donné, je crois que la deuxième référence à :bind devrait être remplacé par quelque chose de différent car cela ne se fait pas dans un ordre séquentiel. Aussi, renommé la variable bind pour se débarrasser de la confusion.

bind_dict = {bind:"var" : diff:"ciao"}
sql = "select * from sometable where somefield=:bind and otherfield=:diff"
cur.prepare(sql)
cur.execute(sql, bind_dict )

Cet article date de 2007 et montre que vous pouvez utiliser un dictionnaire: http://www.Oracle.com/technetwork/articles/dsl/prez-python-queries-101587.html

4
Tyler Christian