使用Python将大数据量Dataframe插入Oracle库及ORA-01843报错求助
问题根因
你遇到的ORA-01843: not a valid month报错核心原因是日期格式不匹配:
- DataFrame中的
CL_CREATED_DATE、CL_MODIFIED_DATE两个字段是字符串格式,默认传入Oracle时会按照数据库的NLS_DATE_FORMAT参数解析 - 你字符串的格式为
日/月/年 时:分(或月/日/年 时:分),和Oracle默认的日期解析规则不一致,导致月份识别失败
解决方案
提供两种可直接落地的修改方式,同时附50万行批量插入的性能优化方案:
方案1:SQL层显式指定日期解析格式(无需修改DataFrame内容)
直接修改插入SQL,用Oracle内置的TO_DATE函数指定字符串的日期格式即可,格式符根据你实际的日期规则调整:
- 如果你的日期格式是
日/月/年 时:分,格式符写'DD/MM/YYYY HH24:MI' - 如果你的日期格式是
月/日/年 时:分,格式符写'MM/DD/YYYY HH24:MI'
修改后的插入语句如下:
cursor.executemany(""" INSERT INTO UCIDBA.FUT_CLIENT_LIST_COPY VALUES (:1,:2,:3,:4,:5,:6,:7, TO_DATE(:8, 'DD/MM/YYYY HH24:MI'), :9, TO_DATE(:10, 'DD/MM/YYYY HH24:MI'), :11) """, rows)
方案2:DataFrame层提前转换为datetime类型(更稳妥,避免格式依赖)
将两个日期字段提前转换为Python datetime类型,cx_Oracle可直接识别该类型插入Oracle DATE字段,不需要依赖数据库的日期格式配置:
# 读取CSV后新增两行转换逻辑 data_df['CL_CREATED_DATE'] = pd.to_datetime(data_df['CL_CREATED_DATE'], format='%d/%m/%Y %H:%M') data_df['CL_MODIFIED_DATE'] = pd.to_datetime(data_df['CL_MODIFIED_DATE'], format='%d/%m/%Y %H:%M') # 后续转tuple、执行插入的逻辑保持不变即可 rows = [tuple(x) for x in data_df.values]
50万行批量插入性能优化
你当前用的executemany本身就是批量插入的最优选择,只需加两个配置即可大幅提升插入速度:
- 调整游标数组大小:
cursor.arraysize = 10000,默认值仅为100,调大后可以减少和数据库的交互次数 - 可选添加批量错误参数:
cursor.executemany(sql, rows, batcherrors=True),避免单条数据错误导致全量插入失败,执行后可通过cursor.getbatcherrors()查看异常行信息
完整修改后参考代码
import cx_Oracle import pandas as pd ip = '192.168.213.151' port = 1515 SID = 'devnc12c' print("cx_oracle version", cx_Oracle.version) dsn_tns = cx_Oracle.makedsn(ip, port, SID) connection = cx_Oracle.connect('NCSWEB', 'Ncvvv##234', dsn_tns) cursor = connection.cursor() # 调整批量插入的数组大小 cursor.arraysize = 10000 print("connection successful") fileName = r'C:\Users\ncdex1124\Desktop\New folder\file10.csv' data_df = pd.read_csv(fileName) # 转换日期字段为datetime类型 data_df['CL_CREATED_DATE'] = pd.to_datetime(data_df['CL_CREATED_DATE'], format='%d/%m/%Y %H:%M') data_df['CL_MODIFIED_DATE'] = pd.to_datetime(data_df['CL_MODIFIED_DATE'], format='%d/%m/%Y %H:%M') print(data_df) print(data_df.info()) rows = [tuple(x) for x in data_df.values] cursor.executemany("INSERT INTO UCIDBA.FUT_CLIENT_LIST_COPY VALUES (:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11)", rows) connection.commit() # 关闭连接 cursor.close() connection.close()
内容的提问来源于stack exchange,提问作者Alok Sharma
相关产品推荐
相关产品推荐

