【问题标题】:Python to stored procedures - The first argument to execute must be a string or unicode queryPython 到存储过程 - 要执行的第一个参数必须是字符串或 unicode 查询
【发布时间】:2019-10-09 23:55:56
【问题描述】:

我有一个包含 50 多个参数的存储过程,在 SQL Server 上的表中插入(基本上是通过存储过程插入数据帧)。 当我运行代码时,出现以下错误:

要执行的第一个参数必须是字符串或 unicode 查询。

我尝试了以下语法,但总是出现相同的错误:

cursor = engine.raw_connection().cursor()
#1
df.apply(lambda row: cursor.execute('EXEC MyProcedure(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',row.values), axis=1)
#2
df.apply(lambda row: cursor.execute('EXEC MyProcedure?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?',row.values), axis=1)
#3
df.apply(lambda row: cursor.execute("""EXEC MyProcedure(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",row.values), axis=1)
results = list(cursor.fetchall())
#4
df.apply(lambda row: cursor.execute(text('EXEC MyProcedure(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',row.values)), axis=1)
#5
df.apply(lambda row: cursor.execute('EXEC MyProcedure',row.values), axis=1)
cursor.close()

这里不支持cursor.callproc(),所以我必须通过EXECCALL 请求。
所以我相信它来自我的参数处理,但我不知道如何解决它。由于我有 57 个参数,因此我试图避免必须尽可能多地命名所有参数...
我的第一个愿望是通过将过程名称作为我的 python 函数的参数传递来使代码运行任何过程,但由于它无法运行,我假设更容易。 该过程已通过 SQL Server Management 直接在数据库上执行并且工作正常。

【问题讨论】:

  • “引擎”是什么样的对象?我认为错误消息表明 execute() 方法的参数存在问题。此外,如果您的 proc 使用 57(!) 参数,则可能存在设计问题。
  • engine 是一个 sqlalchemy 引擎。它有 57 个参数,因为该表有 57 列
  • 这就是我建议重新设计的原因。通常,您不应将行逐列传递给 proc。想象一下,您添加(或删除)一列。您的所有代码都必须更改。如果可能的话,最好将密钥传递给 proc 并让它自己获取行。
  • 您使用的是哪种方言/DBAPI 选项? PyODBC mxODBC pymssql zxJDBC for Jython adodbapi?我想知道这是否可能是编码问题
  • 我用的是pyodbc最新驱动版本

标签: python sql-server sqlalchemy pyodbc


【解决方案1】:

您可以通过使用 pyodbc 的 Cursor#executemany 方法来简化事情:

cnxn = engine.raw_connection()
cnxn.autocommit = True
crsr = cnxn.cursor()

# prepare test environment
crsr.execute("TRUNCATE TABLE MyTable")  # clear previous test data, if any
# prepare test data
df = pd.DataFrame([(1, 'Alfa'), (2, 'Bravo')], columns=['id', 'txt'])

sql = "{CALL MyProcedure (?, ?)}"
rows = df.itertuples(index=False)
crsr.executemany(sql, rows)

# verify results
results = crsr.execute("SELECT * FROM MyTable").fetchall()
print(results)
# [(1, 'Alfa'), (2, 'Bravo')]

【讨论】:

  • 我看不出它与我的 df.apply() 相比如何简化,它已经在行上迭代
猜你喜欢
  • 2013-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-07
  • 1970-01-01
  • 2018-09-14
相关资源
最近更新 更多