You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python写入pandas数据到MS SQL Server出现TDS错误的原因排查

报错根本原因

报错指向的第9个参数,对应INSERT语句里的Entry_Date字段,核心问题是pandas的NaN/NaT和SQL Server的空值NULL不兼容:

  1. pandas里的空值NaN底层是numpy.float64类型,即使是日期字段里的空值NaT,在逐行取数传给ODBC驱动时,也不会被自动识别为SQL的NULL,反而会被当成非法的浮点值传入datetime类型的字段,直接触发TDS流校验错误。
  2. 你提到ENTRY_PLAZA、ENTRY_DATE字段存在部分NaN值,刚好和报错指向的参数位置完全吻合,和你核对的字段类型定义无关,是空值类型不匹配导致的。
修复方案

按以下步骤处理即可解决:

  • 第一步:统一替换DataFrame中的空值,把所有pandas自带的NaN/NaT替换为Python原生的None——只有原生None会被pyodbc/ODBC驱动正确识别为SQL Server的NULL值,替换代码:
    # 先把所有空值替换为原生None
    df = df.where(pd.notna(df), None)
    
  • 第二步:提前强制对齐字段类型,避免隐式转换出错:
    # 日期字段统一转datetime类型,转换失败的值强制置空再替换为None
    df["POSTING_DATE"] = pd.to_datetime(df["POSTING_DATE"], errors="coerce")
    df["ENTRY_DATE"] = pd.to_datetime(df["ENTRY_DATE"], errors="coerce")
    df["EXIT_DATE"] = pd.to_datetime(df["EXIT_DATE"], errors="coerce")
    # 数值字段统一转数值类型,转换失败的值强制置空
    df["MILES"] = pd.to_numeric(df["MILES"], errors="coerce")
    df["TOLL_AMOUNT"] = pd.to_numeric(df["TOLL_AMOUNT"], errors="coerce")
    # 类型转换完再做一次空值替换
    df = df.where(pd.notna(df), None)
    
  • 第三步:修正插入逻辑,逐行插入时直接传入处理后的行元组即可,不需要手动逐个取row[1]到row[15],避免位置数错:
    # itertuples加index=False,就不会带最前面的索引位
    for row in df.itertuples(index=False):
        MsExe.execute("""
            INSERT INTO test_tolls_table_temp (PostingDate, Source, ReadType, PPTagID, ETagID_Plate, EquipID, Agency, Entry_Plaza, Entry_Date, Exit_Plaza, Exit_Date, Toll_Class, Miles, Toll_Amount, ID)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """, row)
    # 记得执行完批量提交
    MsExe.commit()
    

如果数据量较大,不建议用逐行循环插入的写法,可以直接用pandas自带的to_sql方法配合SQLAlchemy连接做批量插入,性能会高很多,也能自动处理大部分类型兼容问题。


内容的提问来源于stack exchange,提问作者Oscar Gutierrez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 05:09:25