将含空值的复杂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}")
关键说明
- 参数绑定的优势:自动处理数据类型映射(数值、日期、字符串),同时将Python的
None直接转为Oracle的NULL,完全避免手动拼接SQL的类型错误和注入风险。 - 空值处理逻辑:Pandas的
NaN(数值/字符串)、NaT(日期)无法直接被cx_Oracle识别,必须转为Python的None,才能正确映射为Oracle的NULL。 - 批量插入:使用
executemany比循环iterrows单条插入效率高很多,即使只有10行数据,也是更规范的写法。
内容的提问来源于stack exchange,提问作者kgs_doc
相关产品推荐
相关产品推荐

