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

使用Cx_Oracle executemany批量插入字典列表触发TypeError问题

问题根源

当使用cx_Oracle的executemany批量插入字典列表时,驱动会根据列表中第一个字典的参数类型推断整个批次的参数类型。你的两个字典中,第一个的birthdate是datetime对象,因此驱动会要求后续所有行的birthdate也必须是datetime类型;但第二个字典的birthdate是空字符串'',无法匹配datetime类型,从而抛出类型错误。

单独处理每个字典时,驱动会针对单个行重新推断类型:处理第一个字典时按datetime处理,处理第二个字典时,空字符串可能被隐式转换为NULL,因此不会报错。

解决方案

方案1:统一将空字符串替换为None

cx_Oracle会将None映射为SQL的NULL,这是DATE类型字段空值的正确表示方式。在插入前预处理数据:

def prepare_debtor_rows(rows):
    for row in rows:
        # 处理birthdate字段,空字符串替换为None
        if row.get('birthdate') == '':
            row['birthdate'] = None
        # 同步处理其他可能的空字段
        for key in ['lastname', 'firstname', 'patronymicname', 'birthplace']:
            if row.get(key) == '':
                row[key] = None
    return rows

def send_data(connection , rows):
    try:
        target_rows = prepare_debtor_rows(rows[23:25])
        with connection.cursor() as cursor:
            sql = """
                INSERT INTO debtors(
                    bankruptID,category,lastname,firstname,patronymicname,
                    fullname,inn,snils,ogrn,region,address,birthdate,
                    birthplace,guid,uploadBatchId
                ) VALUES (
                    :bankruptID,:category,:lastname,:firstname,:patronymicname,
                    :fullname,:inn,:snils,:ogrn,:region,:address,:birthdate,
                    :birthplace,:guid,:uploadBatchId
                )
            """
            cursor.executemany(sql, target_rows)
            connection.commit()
    except Exception as e:
        print(f"插入失败: {str(e)}")
        connection.rollback()

方案2:显式指定参数类型

通过cursor.setinputsizes()强制指定每个参数的数据库类型,避免驱动自动推断出错(建议配合方案1使用,确保空值格式正确):

import cx_Oracle

def send_data(connection , rows):
    try:
        target_rows = prepare_debtor_rows(rows[23:25])
        with connection.cursor() as cursor:
            # 显式指定每个参数的类型
            cursor.setinputsizes(
                bankruptID=int,
                category=str,
                lastname=str,
                firstname=str,
                patronymicname=str,
                fullname=str,
                inn=str,
                snils=str,
                ogrn=str,
                region=str,
                address=str,
                birthdate=cx_Oracle.DATE,
                birthplace=str,
                guid=str,
                uploadBatchId=str
            )
            sql = """
                INSERT INTO debtors(
                    bankruptID,category,lastname,firstname,patronymicname,
                    fullname,inn,snils,ogrn,region,address,birthdate,
                    birthplace,guid,uploadBatchId
                ) VALUES (
                    :bankruptID,:category,:lastname,:firstname,:patronymicname,
                    :fullname,:inn,:snils,:ogrn,:region,:address,:birthdate,
                    :birthplace,:guid,:uploadBatchId
                )
            """
            cursor.executemany(sql, target_rows)
            connection.commit()
    except Exception as e:
        print(f"插入失败: {str(e)}")
        connection.rollback()

关键注意点

  • executemany的类型推断是批次级别的,而非逐行推断,这是批量插入性能优化的一部分,但会导致混合类型的行报错。
  • 数据库DATE类型字段的空值必须用NULL(对应Python的None),空字符串不是有效的DATE值,即使单独插入时未报错,也属于驱动的隐式兼容,不推荐依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 16:25:33