【问题标题】:Python cx_Oracle bind variablesPython cx_Oracle 绑定变量
【发布时间】:2015-12-28 09:27:45
【问题描述】:

我是 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。

【问题讨论】:

    标签: python cx-oracle bind-variables


    【解决方案1】:

    您在滥用绑定。

    使用 cx_Oracle 绑定变量有三种不同的方式see here

    1) 通过将元组传递给带有编号变量的 SQL 语句:

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

    2) 通过将关键字参数传递给带有命名变量的 SQL 语句:

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

    3) 通过将字典传递给带有命名变量的 SQL 语句:

    sql = "select * from sometable where somefield = :myField 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 会理解它需要一个变量。这是一个命名变量,通过名称bind 链接。然后,您应该将参数作为命名参数提供,如下所示:

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

    或者像这样使用字典:

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

    但是,由于 cx_Oracle 接收的是一个元组,它会在一个绑定中回退,就像您的 SQL 语句是:

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

    当您传递bind['var'] 两次时,这只是字符串"ciao"。它将两个元组项映射到编号变量:

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

    这是偶然运行的,但代码非常具有误导性。

    要绑定单个值的元组

    另请注意,第一个选项需要一个元组。但是,如果您要绑定单个值,则可以使用此表示法创建单个值的元组:

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

    [编辑]:感谢@tyler-christian 提到 cx_Oracle 支持传递 dict。

    【讨论】:

    • 对我来说,它缺少单项元组中的尾随逗号。哦!
    • @Rob,确实:type((1,)) = ,但是 type((1)) =
    • 在第二个和第三个例子中,SQL语句中是否有错字(my_field应该是myField)还是根本不重要?
    【解决方案2】:

    @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
    )
    

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

    在给定的示例中,我认为对 :bind 的第二次引用需要替换为不同的内容,因为它不是按顺序完成的。另外,重命名变量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

    【讨论】:

    • 感谢您指出实际上可以使用字典这一事实。我的答案已相应更新。
    猜你喜欢
    • 1970-01-01
    • 2011-11-02
    • 1970-01-01
    • 2018-01-07
    • 2020-09-14
    • 2021-06-16
    • 2021-12-17
    • 1970-01-01
    相关资源
    最近更新 更多