Python结合pandas与SQLAlchemy导入CSV到Oracle报ORA-00932数据类型错误
pandas写入Oracle报ORA-00932: inconsistent datatypes: expected DATE got CLOB 解决方法
报错原因
触发该错误的核心逻辑:
pd.read_csv通过parse_dates解析日期时,只要列内存在空值、格式不匹配的非法日期值,整列dtype会从datetime64降级为object- SQLAlchemy的Oracle方言默认将
object类型列映射为CLOB类型,而目标表对应字段为DATE类型,类型校验不通过直接抛出错误
逐列排查的思路可行,但不需要逐列调试,通过以下两种方案可以直接解决全量日期列的类型问题。
解决方案
方案1:显式指定写入列类型(稳定性最高,优先使用)
调用to_sql时通过dtype参数强制指定列类型,跳过默认的类型自动推断逻辑,从根源避免CLOB类型映射错误。
from sqlalchemy.types import DATE, VARCHAR2, NUMBER import pandas as pd from sqlalchemy import create_engine # 原有CSV读取逻辑 headers = ['LINE_START_DATE', 'LINE_END_DATE'] dtypes = {'LINE_START_DATE': 'str', 'LINE_END_DATE': 'str'} parse_dates = ['LINE_START_DATE', 'LINE_END_DATE'] df = pd.read_csv(processpath+filename, sep=',', index_col=False, dtype=dtypes, names=headers, parse_dates=parse_dates) # 构造类型映射字典,所有日期列统一指定为DATE类型,其余字段按实际业务类型补充 sql_dtype_map = { 'LINE_START_DATE': DATE(), 'LINE_END_DATE': DATE(), # 其余日期列按相同格式追加即可 # 非日期字段示例:'ORDER_NO': VARCHAR2(64), 'AMOUNT': NUMBER(12,2) } engine = create_engine(f'oracle://{username}:{password}{database}') df.to_sql( name=table, con=engine, if_exists='append', index=False, dtype=sql_dtype_map )
方案2:写入前强制转换日期列类型
如果不想手动维护类型映射,可以在读取CSV后统一强制转换所有日期列格式,处理非法值和空值,保证列dtype为pandas可识别的datetime类型:
# 把所有日期列名加入该列表 date_columns = ['LINE_START_DATE', 'LINE_END_DATE'] for col in date_columns: # 强制转换日期格式,非法值统一转为NaT,写入Oracle时会自动识别为DATE类型空值 df[col] = pd.to_datetime(df[col], errors='coerce')
执行完转换后可以通过print(df[date_columns].dtypes)校验,所有列显示为datetime64[ns]即可正常写入。如果某列转换后仍为object类型,说明列内存在无法自动转换的异常字符串,需要先做数据清洗。
避坑说明
- 不要在
read_csv中给日期列设置dtype='str',该参数会干扰parse_dates的自动转换逻辑,容易生成混合类型的object列 - 如果是通过
to_sql自动创建目标表(而非提前建表的append模式),必须使用方案1显式指定类型,否则自动建表会将日期列直接创建为CLOB字段,后续写入必然报错 - 建议将SQLAlchemy版本升级到1.4及以上,1.3及以下旧版本对pandas datetime类型的Oracle映射存在已知bug
内容的提问来源于stack exchange,提问作者cgc123
相关产品推荐
相关产品推荐

