【问题标题】:How to solve for pyodbc.ProgrammingError: The second parameter to executemany must not be emptypyodbc.ProgrammingError如何解决:executemany的第二个参数不能为空
【发布时间】:2020-12-01 22:25:35
【问题描述】:

您好,我在将数据从一个数据库传输到另一个数据库时遇到问题。我使用 msql db 上的表中的字段创建了一个列表,使用该列表查询和 oracle db 表(使用 where 语句中的初始列表过滤结果)然后将查询结果加载回 msql db。

程序在前几次迭代中运行,但随后出错,出现以下错误 ( 回溯(最近一次通话最后): 文件“C:/Users/1/PycharmProjects/DataExtracts/BuyerGroup.py”,第 67 行,在 insertIntoMSDatabase(idString) insertIntoMSDatabase 中的文件“C:/Users/1/PycharmProjects/DataExtracts/BuyerGroup.py”,第 48 行 mycursor.executemany(sql, val) pyodbc.ProgrammingError:executemany的第二个参数不能为空。)

我似乎无法在网上找到解决此错误消息的指南。我觉得这可能是一个简单的解决方案,但我就是无法到达那里......

# import libraries
import cx_Oracle
import pyodbc
import logging
import time
import re
import math
import numpy as np

logging.basicConfig(level=logging.DEBUG)

conn = pyodbc.connect('''Driver={SQL Server Native Client 11.0};
                         Server='servername';
                         Database='dbname';
                         Trusted_connection=yes;''')
b = conn.cursor()
dsn_tns = cx_Oracle.makedsn('Hostname', 'port', service_name='name')
conn1 = cx_Oracle.connect(user=r'uid', password='pwd', dsn=dsn_tns)
c = conn1.cursor()

beginTime = time.time()

bind = (b.execute('''select distinct field1
                     from [server].[db].[dbo].[table]'''))
print('MSQL table(s) queried, List Generated')

# formats ids for sql string
def surroundWithQuotes(id):
    return "'" + re.sub(",|\s$", "", str(id)) + "'"

def insertIntoMSDatabase(idString):
    osql = '''SELECT distinct field1, field2
                FROM Database.Table
                WHERE field2 is not null and field3 IN ({})'''.format(idString)
    c.execute(osql)
    claimsdata = c.fetchall()
    print('Oracle table(s) queried, Data Pulled')

    mycursor = conn.cursor()
    sql = '''INSERT INTO [dbo].[tablename] 
                (
                 [fields1]
                ,[field2]
                )
            VALUES (?,?)'''

    val = claimsdata
    mycursor.executemany(sql, val)
    conn.commit()

ids = []
formattedIdStrings = []

# adds all the ids found in bind to an iterable array
for row in bind:
    ids.append(row[0])

# splits the ids[] array into multiple arrays < 1000 in length
batchedIds = np.array_split(ids, math.ceil(len(ids) / 1000))

# formats the value inside each batchedId to be a string
for batchedId in batchedIds:
    formattedIdStrings.append(",".join(map(surroundWithQuotes, batchedId)))

# runs insert into MS database for each batch of IDs
for idString in formattedIdStrings:
    insertIntoMSDatabase(idString)

print("MSQL table loaded, Data inserted into destination")

endTime = time.time()

print("Program Time Elapsed: ",endTime-beginTime)

conn.close()
conn1.close()

【问题讨论】:

  • SQL Server != Oracle
  • 看起来您需要测试val(又名claimsdata)是否为空列表(如果 SELECT 未返回任何行则会发生这种情况),如果是,则不要调用 .executemany()
  • 除了其他建议外,使用 cx_Oracle 尝试使用绑定变量来阻止您的字符串连接可能容易受到的 SQL 注入安全攻击(并且绑定也可能有助于提高性能),请参阅 Binding Multiple Values to a SQL WHERE IN Clause。并使用 arraysize 和 prefetchrows 调整数据传输,请参阅Tuning Fetch Performance
  • 我按照@GordThompson 的建议进行了测试,如果 len(val)

标签: oracle python-3.7 pyodbc


【解决方案1】:

mycursor.executemany(sql, val)

pyodbc.ProgrammingError: 第二个参数executemany不能为空。

在调用 .executemany() 之前,您需要验证 val 不是一个空列表(如果在不返回任何行的 SELECT 语句上调用 .fetchall() 就是这种情况),例如,

if val:
    mycursor.executemany(sql, val)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-07
    • 2014-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-12
    • 2021-04-02
    • 1970-01-01
    相关资源
    最近更新 更多