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

将含空值的复杂Pandas DataFrame导入Oracle表的技术问题

解决Pandas DataFrame导入Oracle时的空值与类型匹配问题

问题根源

你遇到的ORA-01722错误,本质是错误地将空值填充为字符串"NULL",导致插入数值字段时,Oracle试图把字符串"NULL"解析成数字,引发类型不匹配。另外,直接拼接SQL字符串的方式既不安全,也无法正确处理不同数据类型的空值映射。

正确处理方案

核心思路:保留Pandas中的空值(NaN/NaT),通过cx_Oracle参数绑定自动将Python的None(Pandas的NaN转换后)映射为Oracle的NULL,同时自动适配字段类型。

步骤1:正确读取CSV并处理空值

读取CSV时不要提前填充空值,保留原始的NaN,后续通过类型转换和参数绑定处理:

import pandas as pd
import cx_Oracle
from datetime import datetime

# 读取CSV,默认会把空白单元格转为NaN
surveyData = pd.read_csv(r"FM_Sample.csv", delimiter=',', index_col=False)

# 处理日期类型字段(替换成你的实际日期列名)
date_cols = ["DATE_COL1", "DATE_COL2"]
surveyData[date_cols] = surveyData[date_cols].apply(pd.to_datetime, errors='coerce')

步骤2:使用参数绑定构建插入语句

避免手动拼接SQL字符串,改用占位符:1, :2...,让cx_Oracle自动处理类型和空值:

# Oracle表字段列表(需与DataFrame列顺序对应)
oracleFieldsList = ['FO_NUM', 'WR_ID', ..., 'FILE_NO', 'UMW']
oracle_fields = ",".join(oracleFieldsList)

# 构建带占位符的INSERT语句
placeholders = ",".join([f":{i+1}" for i in range(len(oracleFieldsList))])
sql = f"INSERT INTO ORACLE_TABLE ({oracle_fields}) VALUES ({placeholders})"

def insertDFrecs(sql, data):
    connstr = 'URL:port/dbname'
    conn = cx_Oracle.connect('user', 'pass', connstr)
    curs = conn.cursor()
    try:
        # 批量插入,效率远高于单条循环
        curs.executemany(sql, data)
        conn.commit()
    except Exception as e:
        conn.rollback()
        raise e
    finally:
        curs.close()
        conn.close()

步骤3:将DataFrame转换为适合参数绑定的格式

把DataFrame的每一行转为元组,同时将NaN/NaT替换为Python的None(cx_Oracle会自动把None转为Oracle的NULL):

def df_to_db_data(df, fields):
    # 数值列:NaN转None
    num_cols = df.select_dtypes(include=['int64', 'float64']).columns
    df[num_cols] = df[num_cols].where(pd.notnull(df[num_cols]), None)
    # 日期列:NaT转None
    date_cols = df.select_dtypes(include=['datetime64']).columns
    df[date_cols] = df[date_cols].where(pd.notnull(df[date_cols]), None)
    # 字符串列:NaN转None
    str_cols = df.select_dtypes(include=['object']).columns
    df[str_cols] = df[str_cols].where(pd.notnull(df[str_cols]), None)
    # 转为元组列表
    return [tuple(row) for row in df[fields].values]

# 生成插入数据
db_data = df_to_db_data(surveyData, oracleFieldsList)

# 执行插入
try:
    insertDFrecs(sql, db_data)
    print("数据导入成功")
except Exception as e:
    print(f"导入失败:{e}")

关键说明

  1. 参数绑定的优势:自动处理数据类型映射(数值、日期、字符串),同时将Python的None直接转为Oracle的NULL,完全避免手动拼接SQL的类型错误和注入风险。
  2. 空值处理逻辑:Pandas的NaN(数值/字符串)、NaT(日期)无法直接被cx_Oracle识别,必须转为Python的None,才能正确映射为Oracle的NULL。
  3. 批量插入:使用executemany比循环iterrows单条插入效率高很多,即使只有10行数据,也是更规范的写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 04:35:03