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

Python Pandas中将NaN转为Oracle空值遇DPI-1055错误求助

解决Oracle插入DataFrame时NaN导致的DPI-1055错误

首先咱们先拆解你遇到的核心问题:

  1. 你用df.where(pd.notnull(df), None)没生效,是因为pandas的where方法默认返回新的DataFrame,不会修改原数据——你没把结果赋值回df,所以原表的NaN根本没被替换。
  2. 就算你做了赋值,pandas的数值类型列(比如float64)无法直接存储None,会自动把None转回NaN,导致替换操作等于没做,插入时还是触发错误。

接下来给你几个可行的解决方案,按推荐程度排序:

方案1:正确替换NaN为None并处理数值列类型

先把所有NaN替换为None,同时把数值列转为object类型(这样才能保留None,避免被自动转回NaN)。修改后的代码如下:

import pandas as pd

def insertData(table_name, schema_name, df):
    if not df.empty:
        # 关键修改:先转object类型,再替换NaN为None
        df = df.astype(object).where(pd.notnull(df), None)
        values = df.to_dict(orient='records')
        table = sa.Table(table_name , conndict['meta'], autoload=True, schema=schema_name)
        result_proxy = conndict['conn'].execute(table.insert(), values)
        return result_proxy
    else:
        return None

如果担心全表转object影响性能,可以只针对数值列单独处理:

def insertData(table_name, schema_name, df):
    if not df.empty:
        # 处理数值列:将NaN替换为None
        num_cols = df.select_dtypes(include=['int64', 'float64']).columns
        for col in num_cols:
            df[col] = df[col].apply(lambda x: None if pd.isna(x) else x)
        # 处理非数值列:直接替换NaN为None
        non_num_cols = df.select_dtypes(exclude=['int64', 'float64']).columns
        df[non_num_cols] = df[non_num_cols].where(pd.notnull(df[non_num_cols]), None)
        
        values = df.to_dict(orient='records')
        table = sa.Table(table_name , conndict['meta'], autoload=True, schema=schema_name)
        result_proxy = conndict['conn'].execute(table.insert(), values)
        return result_proxy
    else:
        return None

这样处理后,DataFrame里的NaN会被替换成Python的None,SQLAlchemy插入时会自动把None映射为Oracle的NULL,完美解决DPI-1055错误。

方案2:利用SQLAlchemy类型绑定自动转换NaN

如果你不想修改DataFrame的类型,可以在插入语句中指定数值列的类型,让SQLAlchemy自动把NaN转为NULL:

from sqlalchemy import Numeric, bindparam

def insertData(table_name, schema_name, df):
    if not df.empty:
        values = df.to_dict(orient='records')
        table = sa.Table(table_name , conndict['meta'], autoload=True, schema=schema_name)
        
        # 为数值列创建带类型绑定的参数,自动处理NaN为NULL
        insert_values = []
        for row in values:
            bind_params = {}
            for col, val in row.items():
                if table.c[col].type.python_type in (int, float):
                    bind_params[col] = bindparam(col, type_=Numeric, nullable=True)
                else:
                    bind_params[col] = val
            insert_values.append(bind_params)
        
        result_proxy = conndict['conn'].execute(table.insert(), insert_values)
        return result_proxy
    else:
        return None

这个方法的核心是用bindparam指定数值类型,SQLAlchemy会自动识别NaN并转为Oracle的NULL。

方案3:使用pandas内置的to_sql方法(最简洁)

如果你的场景允许,直接用pandas的to_sql会更省心,它已经内置了NaN转NULL的处理逻辑:

def insertData(table_name, schema_name, df):
    if not df.empty:
        df.to_sql(
            name=table_name,
            schema=schema_name,
            con=conndict['conn'],
            if_exists='append',  # 可根据需求选择append/replace/fail
            index=False
        )
        return True
    else:
        return None

to_sql会自动处理数值列的NaN,将其转为Oracle的NULL,无需手动替换,代码也更简洁。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:32:01