Python向MS SQL插入DataFrame遇HY105错误及异常求助
问题:API加载的DataFrame插入MS SQL失败,报错参数类型错误及字符串拼接错误
错误信息
- 插入操作触发的错误:
pyodbc.ProgrammingError: ('Invalid parameter type. param-index=1 param-type=method', 'HY105')
- 异常处理环节触发的错误:
TypeError: can only concatenate str (not "set") to str
代码
def insert(db_connect): try: cursor = db_connect.cursor() sql_query = cursor.execute("Select * from Dashboard") allrows = sql_query.fetchall() totalrows = len(allrows) if totalrows > 0: cursor.execute("Truncate table Dashboard") logging.info('Truncated table : ' + today.strftime("%d-%m-%Y %H-%M")) text_data = response.text json_dict = json.loads(text_data) df = pd.DataFrame.from_dict(json_dict["elements"]) print(df.columns.to_list()) for index, row in df.iterrows(): cursor.execute("INSERT INTO Dashboard (SKID,Item,IDate,Warehouse,Location,TDate,Stock,GRN,Lane,Company) values(?,?,?,?,?,?,?,?,?,?)", row.mnum, row.item, row.idat, row.cwar, row.loca, row.trdt, row.stks, row.cval, row.valu1_0, row.company) logging.info('Data inserted successfully : ' + today.strftime("%d-%m-%Y %H-%M")) #os.getcwd() ArchiveFilePath = os.path.join(ROOT_DIR, 'Archive\Dashboard_'+ d1 +'.xlsx') column_names = ['Mnum', 'Item','Idat','Cwar', 'Loca', 'Trdt', 'Stks', 'Cval', 'Valu 1', 'Company'] df.to_csv(ArchiveFilePath,index=False,header=column_names, columns=['mnum','item','idat', 'cwar','loca','trdt', 'stks', 'cval', 'valu1', 'company' ]) logging.info('File Created Successfully : ' + today.strftime("%d-%m-%Y %H-%M")) except Exception as e: print('Could not insert to database') logging.info('Could not insert to database : ' + {str(e)})
SQL表结构
Dashboard表字段信息:
- SKID (nvarchar(50))
- Item (nvarchar(50))
- IDate (datetime)
- Warehouse (nvarchar(50))
- Location (nvarchar(50))
- TDate (datetime)
- Stock (float)
- GRN (nvarchar(50))
- Lane (nvarchar(50))
- Company (nvarchar(50))
解决方案
1. 修复参数类型错误(pyodbc.ProgrammingError)
问题根源是cursor.execute的参数传递不符合要求:pyodbc要求参数以元组/列表形式传入,且逐行插入效率极低。推荐两种修复方式:
方案一(推荐:用pandas内置方法批量写入)
删除原循环插入代码,改用to_sql完成数据写入,同时自动替代truncate逻辑:
# 将DataFrame列名映射为SQL表字段名 df.rename(columns={ 'mnum': 'SKID', 'item': 'Item', 'idat': 'IDate', 'cwar': 'Warehouse', 'loca': 'Location', 'trdt': 'TDate', 'stks': 'Stock', 'cval': 'GRN', 'valu1_0': 'Lane', 'company': 'Company' }, inplace=True) # if_exists='replace'会先删除原表再重建,等价于truncate+插入 df.to_sql('Dashboard', db_connect, if_exists='replace', index=False)
方案二(坚持逐行插入)
将参数打包成元组传递给cursor.execute:
cursor.execute( "INSERT INTO Dashboard (SKID,Item,IDate,Warehouse,Location,TDate,Stock,GRN,Lane,Company) values(?,?,?,?,?,?,?,?,?,?)", (row.mnum, row.item, row.idat, row.cwar, row.loca, row.trdt, row.stks, row.cval, row.valu1_0, row.company) )
同时需确认row.xxx是DataFrame的列值,而非Series内置方法(避免列名与方法重名)。
2. 修复字符串拼接错误(TypeError)
异常处理中{str(e)}创建了集合,无法与字符串拼接,修改为:
# 直接拼接字符串 logging.info('Could not insert to database : ' + str(e)) # 或用更简洁的f-string写法 logging.info(f'Could not insert to database : {str(e)}')
其他潜在问题修复
- 确保
response、today、d1、ROOT_DIR变量在函数内可访问或作为参数传入; - 修正归档文件路径:用
os.path.join正确拼接,且to_csv对应.csv后缀:ArchiveFilePath = os.path.join(ROOT_DIR, 'Archive', f'Dashboard_{d1}.csv')
内容的提问来源于stack exchange,提问作者Teena
相关产品推荐
相关产品推荐

