使用pyodbc调用含UDT参数的存储过程时出错
解决pyodbc调用带表值参数的存储过程报错问题
报错pyodbc.ProgrammingError: ('Invalid parameter type. param-index=4 param-type=NAType', 'HY105')的核心原因是pyodbc无法直接识别列表元组作为SQL Server表值参数(UDT),同时日期字符串未转换为对应的数据类型。以下是修正方案:
关键修正点
- 必须使用
pyodbc.TableValuedParameter显式封装表值参数,指定对应的SQL Server用户定义表类型名称 - 将DataFrame中的日期字符串转换为Python
datetime对象,匹配SQL ServerDATETIME2类型要求 - 确保DataFrame的列顺序与
DemandType的列定义完全一致
修正后的代码
import pyodbc import pandas as pd from datetime import datetime def uploadDataframeToSQL(inputData: pd.DataFrame): # 转换日期列:字符串转datetime对象 inputData['eptTimeStamp'] = pd.to_datetime(inputData['eptTimeStamp']) conn_str = ( "DRIVER={ODBC Driver 17 for SQL Server};" "SERVER=<my_db_url>;" "DATABASE=<my_db>;" "UID=<my_uid>;" "PWD=<my_pwd>" ) conn = pyodbc.connect(conn_str) cursor = conn.cursor() # 转换为元组列表(确保列顺序与DemandType一致) data_to_insert = [tuple(row) for index, row in inputData.iterrows()] # 用TableValuedParameter封装表值参数,指定UDT类型名 tvp = pyodbc.TableValuedParameter('dbo.DemandType', data_to_insert) # 执行存储过程 cursor.execute('EXEC dbo.MergeDemandUpsert @Demand=?', (tvp,)) conn.commit() cursor.close() conn.close()
额外注意事项
- 确认DataFrame的列顺序严格对应
DemandType的定义:eptTimeStamp、amount、mid、peak、mid2、peak2、Total,表值参数是按位置匹配列,而非列名 - 确保ODBC Driver 17 for SQL Server已正确安装,该版本支持表值参数的完整功能
- 如果DataFrame中存在空值(NaN),需转换为
None,对应SQL Server的NULL值(可通过inputData = inputData.where(pd.notnull(inputData), None)处理)
内容的提问来源于stack exchange,提问作者hozer95
相关产品推荐
相关产品推荐

