使用PYODBC将Pandas DataFrame插入SQL Server表时遭遇HY004无效SQL数据类型错误求助
我帮你排查下这个错误的核心问题,先看你的代码就能发现一个关键疏漏——你在cursor.execute里传入的是整个DataFrame的列(比如final_df.ActivityType),但在iterrows()循环里,你应该用当前循环的row对象来取单个行的值啊!这会导致pyodbc试图把整列数据绑定到单个参数上,直接触发数据类型不匹配的错误。
下面给你一步步的修复方案:
第一步:修正循环内的参数取值逻辑
把代码里的final_df.ActivityType这类整列引用,改成row[列名]的形式,确保每次循环只传入当前行的单个值。比如修正后的执行语句应该是:for index, row in final_df.iterrows(): print(row) cursor.execute("INSERT INTO CourseOutline ([ActivityTypeID] ,[ActivityID],[Sequence],[CourseTypeID] ,[Duration], [MinistryCode] ,[FGCCode] ,[Percentage],[ModuleID] ,[PageNo]) values(?,?,?,?,?,?,?,?,?,?)", row['ActivityType'], row['DBID'], row['Seq'], row['CourseType'], 1, row['MinistryCodes'], row['FGCCodes'], row['Percentage'], row['Module'], row['PgNo']) cnxn.commit() cursor.close()这里要注意:你写的列名要和DataFrame实际列名完全对应,比如表字段是
ActivityTypeID,但你代码里用的是final_df.ActivityType,要核对清楚别搞混。第二步:检查硬编码参数的类型匹配
你代码里硬编码了1(对应Duration)、'MinistryCodes'、'FGCCodes'这几个值,要确认SQL Server表中对应字段的类型是否匹配:- 如果
Duration是整数类型,1没问题;如果是小数类型,可能要写成1.0 - 如果
MinistryCode/FGCCode是整数类型的编码字段,你传字符串就会触发数据类型错误,得改成对应数值
- 如果
第三步:用批量插入替代循环(高效优化方案)
用iterrows()循环插入效率极低,数据量大的时候尤其明显。推荐用pyodbc的executemany方法一次性批量插入,既高效又能避免循环取值的错误:# 提取DataFrame中需要的列并转为列表格式 insert_rows = final_df[['ActivityType', 'DBID', 'Seq', 'CourseType', 'MinistryCodes', 'FGCCodes', 'Percentage', 'Module', 'PgNo']].values.tolist() # 给每个行插入硬编码的Duration值(第5个参数,索引为4) for row in insert_rows: row.insert(4, 1) # 执行批量插入 cursor.executemany("INSERT INTO CourseOutline ([ActivityTypeID] ,[ActivityID],[Sequence],[CourseTypeID] ,[Duration], [MinistryCode] ,[FGCCode] ,[Percentage],[ModuleID] ,[PageNo]) values(?,?,?,?,?,?,?,?,?,?)", insert_rows) cnxn.commit() cursor.close()
如果做完这些还是报错,你可以用final_df.dtypes查看DataFrame的列类型,再和SQL表的字段类型逐一对比,比如pandas的datetime64是否对应SQL的datetime2,float64是否对应SQL的decimal这类需要类型转换的场景。
内容的提问来源于stack exchange,提问作者Usman Rafiq

