Soy un novato en Python, estoy teniendo problemas en el uso de bind variables. Si yo ejecuto el código de abajo todo funciona bien.

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

Lugar si añado otro enlace variable obtengo un error.

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

Me han resuelto con

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

pero no puedo entender por qué el comando anterior no estaba bien.

Que es la manera correcta de usar bind variables? Estoy usando cx_Oracle.

OriginalEl autor Giovanni De Ciantis | 2015-09-30

2 Comentarios

  1. 29

    Que abusan de la unión.

    Hay tres maneras diferentes de unión variables con cx_Oracle como uno puede ver aquí :

    1) por el paso de una tupla a una instrucción SQL con numeradas variables :

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

    2) Por el paso de parámetros de palabra clave para una instrucción SQL con el nombre de las variables :

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

    3) pasando un diccionario para una instrucción SQL con el nombre de las variables :

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

    Observaciones

    ¿Por qué el código de trabajo, entonces ?

    Vamos a tratar de entender lo que sucede aquí :

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

    Oracle va a entender que se espera de una variable. Este es el nombre de una variable, vinculadas por el nombre bind. A continuación, usted debe dar un parámetro como un parámetro con nombre como este :

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

    O el uso de un diccionario, como que :

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

    Sin embargo, como cx_Oracle recibe una tupla en su lugar, ahora se cae en una unión, por número, como si la declaración SQL fue :

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

    Y como se pasa bind['var'] dos veces, que es sólo la cadena "ciao". Es la asignación de la tupla de dos elementos con el número de variables :

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

    Que corre por casualidad, pero el código es muy engañosa.

    Tupla con un valor único para enlazar

    También tenga en cuenta que la primera opción requiere de una tupla. Pero si usted tiene un solo valor para enlazar, usted puede usar esta notación para crear una tupla de un solo valor :

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

    [EDITAR] : Gracias a @tyler-cristiana para mencionar que la aprobación de un diccionario se fue apoyado por cx_Oracle.

    muchas gracias! muy buena explicación!
    Para mí fue que falta el punto y coma final, en un solo elemento de la tupla. D’oh!
    en efecto : tipo((1,)) = <tipo ‘tupla’>, pero de tipo((1)) = <tipo ‘int’>

    OriginalEl autor ffarquet

  2. 4

    @ffarquest dice que el uso de un diccionario no es compatible con cx_Oracle pero es, de hecho, @giovanni-de-ciantis estaba usando de forma incorrecta.


    named_params = {'dept_id':50, 'sal':1000}
    query1 = cursor.execute(
        'SELECT * FROM employees WHERE department_id=:dept_id AND salary>:sal',
        named_params
    )

    O

    query2 = cursor.execute(
        'SELECT * FROM employees WHERE department_id=:dept_id AND salary>:sal',
        dept_id=50,
        sal=1000
    )

    En el ejemplo dado, yo creo que la segunda referencia a :bind tendría que ser reemplazado con algo diferente ya que no es la que se realiza en orden secuencial. También, cambiado el nombre de la variable bind para deshacerse de confusión.

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

    Este artículo es de 2007 muestra que usted puede usar un diccionario:
    http://www.oracle.com/technetwork/articles/dsl/prez-python-queries-101587.html

    Gracias por señalar el hecho de que el uso de un diccionario es realmente posible. Mi respuesta ha sido actualizado en consecuencia.

    OriginalEl autor Tyler Christian

Dejar respuesta

Please enter your comment!
Please enter your name here