Oracle 18c批量插入10万行报ORA-00933/ORA-00001错误如何解决
报错原因及解决方法
1. ORA-00933 SQL命令未正确结束
原因
Oracle默认不支持在单条请求中执行多条用分号拼接的独立INSERT语句,你把两条INSERT语句合并提交就会触发该报错。
解决方法
- 若使用数据库客户端执行,逐行运行单条INSERT语句,或开启客户端的多语句执行权限
- 若在代码中调用(如JDBC场景),可在数据库连接串添加参数
allowMultiQueries=true,或改用JDBC批量执行API(addBatch+executeBatch)
2. ORA-00001 唯一约束违反
原因
该报错由你的INSERT ALL写法的两个问题共同导致:
- Oracle的INSERT ALL语法中,序列
NEXTVAL在整个语句执行周期内仅会生成一次,所有INTO子句取到的ID值完全相同,直接触发主键/唯一键重复 - INSERT ALL尾部的SELECT语句返回多少行,整组INTO插入逻辑就会重复执行多少次,你写的
SELECT 1 FROM schema_name.table_name如果来源表非空,会导致重复插入多轮相同数据,进一步触发约束报错
解决方法
INSERT ALL本身不适合搭配序列生成逐行唯一主键的场景,建议直接更换为更适合批量插入的写法,见下文。
Oracle 10万行量级批量插入的正确方案
根据你的数据来源不同,可选择以下最优方案:
方案1:数据来自其他Oracle表(性能最优)
直接使用INSERT INTO ... SELECT语法,这是Oracle官方推荐的批量插入方式,全程单语句执行,序列会为每一行生成独立值,不会出现重复问题。
示例代码:
INSERT INTO table_name (ID, code, date_t) SELECT schema_name.SEQ$table_name.NEXTVAL, 数据源表.code字段, 数据源表.date字段 FROM 数据源表 WHERE 数据过滤条件;
方案2:数据为程序/脚本生成的离散值
使用PL/SQL的FORALL批量绑定特性,性能比逐行INSERT高数十倍,适合10万行级别的数据插入。
示例代码:
DECLARE -- 定义存储批量数据的集合类型 TYPE code_arr IS TABLE OF VARCHAR2(20) INDEX BY PLS_INTEGER; TYPE date_arr IS TABLE OF DATE INDEX BY PLS_INTEGER; v_codes code_arr; v_dates date_arr; BEGIN -- 填充需要插入的10万条数据 v_codes(1) := '232323232323'; v_dates(1) := TO_DATE('2020-09-01','YYYY-MM-DD'); v_codes(2) := '242424242424'; v_dates(2) := TO_DATE('2020-09-01','YYYY-MM-DD'); -- 循环填充剩余数据 FOR i IN 3..100000 LOOP v_codes(i) := '你的自定义code值' || i; v_dates(i) := TO_DATE('2020-09-01','YYYY-MM-DD'); END LOOP; -- 批量执行插入 FORALL i IN 1..v_codes.COUNT INSERT INTO table_name (ID, code, date_t) VALUES (schema_name.SEQ$table_name.NEXTVAL, v_codes(i), v_dates(i)); COMMIT; END; /
方案3:小批量离散值插入(Oracle 12c及以上版本支持)
12c以上版本支持多值行构造语法,写法更简洁,适合几百到几千行的小批量插入,不建议用于10万行级别(语句过长会影响解析性能)。
示例代码:
INSERT INTO table_name (ID, code, date_t) SELECT schema_name.SEQ$table_name.NEXTVAL, code, date_t FROM ( VALUES ('232323232323', TO_DATE('2020-09-01','YYYY-MM-DD')), ('242424242424', TO_DATE('2020-09-01','YYYY-MM-DD')) -- 剩余行按相同格式追加即可 ) t(code, date_t);
内容的提问来源于stack exchange,提问作者FeoJun
相关产品推荐
相关产品推荐

