pyodbc 执行变量变为@P1

pyodbc execute variable becomes @P1

嗨,我正在做类似的事情:

# pyodbc extension
cursor.execute("select a from tbl where b=? and c=?", x, y)

-- 查询中的某些值由变量提供。但有时该变量在查询中被解释为 @P1

例如:

import pyodbc

ch = pyodbc.connect('DRIVER={SQL Server};SERVER=xxxx;DATABASE=xxx;Trusted_Connection=True')
cur = ch.cursor()

x = 123

cur.execute('''
CREATE TABLE table_? (
  id int IDENTITY(1,1) PRIMARY KEY,
  obj varchar(max) NOT NULL
)
''', x).commit()

这会产生一个名为 table_@P1 的新 table(我想要 table_123

另一个例子:

x = 123

cur.execute('''
CREATE TABLE table_2 (
  id int IDENTITY(1,1) PRIMARY KEY,
  obj varchar(?) NOT NULL
)
''', x).commit()

它报告错误:

ProgrammingError: ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near '@P1'. (102) (SQLExecDirectW)")

同样,变量被解释为 @P1

有人知道如何解决这个问题吗?任何帮助表示赞赏。谢谢-

在您的第一种情况下,参数替换不适用于 table/column 个名称。这对于绝大多数(如果不是全部)数据库平台都是常见的。

在你的第二种情况下,SQL 服务器似乎不支持 DDL 语句的参数替换。 SQL 服务器 ODBC 驱动程序将 pyodbc 参数占位符 (?) 转换为 T-SQL 参数占位符 (@P1, @P2, ...) 因此传递给 SQL 服务器的语句是

CREATE TABLE table_2 (id int IDENTITY(1,1) PRIMARY KEY, obj varchar(@P1) NOT NULL

特别是

exec sp_prepexec @p1 output,N'@P1 int',N'CREATE TABLE table_2 (id int IDENTITY(1,1) PRIMARY KEY, obj varchar(@P1) NOT NULL',123

并且当 SQL 服务器尝试准备该语句时,它需要一个文字值,而不是参数占位符。

因此,在这两种情况下,您都需要使用动态 SQL(字符串格式)来插入适当的值。

有一种方法可以做到这一点。您需要做的是动态构建命令(理想情况下作为 nvarchar(MAX),而不是 varchar(MAX))字符串变量并将该变量传递给 cur.execute() - 或任何其他 - 命令。相应地修改您的第一个示例:

ch = pyodbc.connect( 'DRIVER={SQL Server};SERVER=xxxx;DATABASE=xxx;Trusted_Connection=True' )
cur = ch.cursor()

x = 123

SQL_Commands = 'CREATE TABLE table_' +  str( x )  +  '''    
(
  id int IDENTITY(1,1) PRIMARY KEY,
  obj varchar(max) NOT NULL
) '
'''

cur.execute( SQL_Commands ).commit()

顺便说一句,你不应该试图在一行中做所有事情,如果只是为了避免像这样的问题。我还建议考虑将 "autocommit=True" 添加到您的连接字符串,这样您就不必将 .commit() 附加到 cur.execute()。