使用PyODBC向SQL Server插入数据时偶发无异常但数据丢失问题求助
问题原因分析
- 参数名拼写不一致(高概率):你SQL语句中的字段名为
Condicion(无重音符号),但取值时用的是row.Condición(带重音符号),如果Excel读取生成的DataFrame列名没有重音符号,会导致该字段取值异常,触发静默插入失败,不会抛出可捕获的异常。 - 数据截断/类型不匹配未触发报错:SQL Server默认配置下如果
ANSI_WARNINGS参数为OFF,字符串超过字段长度、数值类型溢出等轻量错误不会触发异常,会直接静默丢弃不符合规则的行,你定义的Estado、Condicion都是定长nchar(10),如果Excel对应字段内容长度超过10,就会触发该问题。 - DataFrame遍历的行异常:你使用
df2.iterrows()遍历数据,该方法不会严格保留原始数据类型,如果Excel中的SAP、Aviso等整数字段读入时被转成浮点数、空值被识别为NaN,PyODBC可能会静默跳过该行插入,不会抛出异常。 - 事务隐式回滚未被捕获:你仅在所有插入完成后执行一次
cnxn.commit(),如果插入过程中出现数据库瞬时断连、死锁导致事务被SQL Server端主动回滚,可能出现客户端未收到异常提示、整批数据全部丢失的情况。 - 动态表名拼接风险:你通过字符串格式化拼接表名,如果
table_name存在特殊字符、或者和库中其他表重名(大小写不敏感的SQL Server实例下),可能出现数据插入到其他表的情况,看起来像是目标表数据丢失。
排查优化方案
# 建议替换单条插入为批量插入,同时增加执行结果校验 params = [] for index, row in df2.iterrows(): # 提前校验字段取值,避免拼写错误 params.append(( row['SAP'], row['Equipo'], row['Estado'], row['Aviso'], row['Fecha'], row['Condicion'], # 统一列名拼写 row['Observaciones'] )) # 批量插入性能更高,也更容易排查整体执行结果 cursor.executemany("INSERT INTO {tab} (SAP,Equipo,Estado,Aviso,Fecha,Condicion,Observaciones) VALUES(?,?,?,?,?,?,?)".format(tab=table_name), params) # 打印受影响行数,确认插入条数是否和DataFrame行数一致 print(f"本次插入影响行数:{cursor.rowcount}")
- 插入前提前校验所有字段的长度、类型是否和SQL表定义匹配,过滤不符合规则的数据。
- 开启SQL Server的
ANSI_WARNINGS ON配置,确保数据异常时能抛出可捕获的错误。 - 每次提交事务前后检查数据库连接状态,避免断连导致的提交失败。
内容的提问来源于stack exchange,提问作者abaetti
相关产品推荐
相关产品推荐

