将参数传递给cursor.execute()时pyodbc中的UnicodeDecodeError,但在将参数直接写入字符串时不会
Posted
技术标签:
【中文标题】将参数传递给cursor.execute()时pyodbc中的UnicodeDecodeError,但在将参数直接写入字符串时不会【英文标题】:UnicodeDecodeError in pyodbc when passing parameters to cursor.execute(), but not when writing parameters directly to string 【发布时间】:2019-01-25 16:15:21 【问题描述】:当尝试使用 pyodbc 将参数传递给准备好的语句时,Python 返回 UnicodeDecodingError。但是,直接将参数添加到prepared statement字符串时,就没有这个错误了。
我使用 Python 3 中的 pyodbc 库和“Oracle in OraDB12Home1”驱动程序在 Windows 10(64 位)上工作。将所有参数直接添加到包含 sql 语句的字符串时,从数据库中检索信息工作正常。
这里有两个抛出上述错误的例子
示例 1
cursor = cnxn.cursor()
sql_statement = "select col1 from ? where col1 is not null;"
params = ("db_name")
cursor.execute(sql_statement,params)
示例 2
cursor = cnxn.cursor()
sql_statement = "select col1 from db_name where col1 is not ?;"
params = ("null")
cursor.execute(sql_statement,params)
两种情况下产生的错误如下:
---------------------------------------------------------------------------
UnicodeDecodeError Traceback (most recent call last)
~\AppData\Local\conda\conda\envs\fasttext\lib\encodings\utf_16_le.py in decode(input, errors)
15 def decode(input, errors='strict'):
---> 16 return codecs.utf_16_le_decode(input, errors, True)
17
UnicodeDecodeError: 'utf-16-le' codec can't decode bytes in position 160-161: illegal encoding
请注意,选择不同的数据库(例如,将“db-name”替换为“different_db_name”)并不能解决问题,仍然会引发相同的错误。
预期行为
我希望得到与以下示例相同的结果,该示例运行时不会出错:
cursor = cnxn.cursor()
sql_statement = "select col1 from db_name where col1 is not null;"
cursor.execute(sql_statement)
另外,请注意传递 不同 参数可以正常工作。例如,以下代码的执行不会引发错误,尽管与上面提供的示例的唯一区别是传递的参数。
cursor = cnxn.cursor()
sql_statement = "select ? from db_name where col1 is not null;"
params = ("col1")
cursor.execute(sql_statement)
【问题讨论】:
【参考方案1】:X is null
和 X is not null
是 SQL 语言的子句 - 请参阅:NULL conditions。
有SQL关键字,这些子句中的NULL
关键字是语法的一部分,你根本不能把关键字作为参数传递。
因此这是不正确的:
sql_statement = "select col1 from db_name where col1 is not ?"
你必须改用这样的东西:
param = "null"
if param == "null":
sql_statement = "select col1 from db_name where col1 is null"
else:
sql_statement = "select col1 from db_name where col1 is not null"
这同样适用于表名 - 它们不能作为绑定变量传递。 我不会解释为什么,关于这个问题有很多答案,例如这个:passing table and column name dynamically using bind variables 因此这是不正确的:
sql_statement = "select col1 from ? where col1 is not null"
你必须改用这个:
param = "db_name"
sql_statement = "select col1 from " + param + " where col1 is not null"
【讨论】:
以上是关于将参数传递给cursor.execute()时pyodbc中的UnicodeDecodeError,但在将参数直接写入字符串时不会的主要内容,如果未能解决你的问题,请参考以下文章
将Datetime作为参数传递给PyODBC的存储过程时出错