20

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

4

2 回答 2

55

您正在滥用绑定。

可以在这里看到,使用 cx_Oracle 绑定变量有三种不同的方式:

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 会理解它需要一个变量。这是一个命名变量,由 name 链接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']两次时,这只是 string "ciao"。它将两个元组项映射到编号变量:

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

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

具有要绑定的单个值的元组

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

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

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

于 2015-11-23T23:32:51.760 回答
5

@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

于 2017-04-12T19:47:28.993 回答