批量插入:有没有办法在违反约束时跳过下一条记录?

Batch insert: is there a way to just skip on next record when a constraint is violated?

我正在使用 mybatis 在 oracle 数据库上执行大量批量插入。

我的过程非常简单:我从文件列表中获取记录,并在对数据执行一些检查后将它们插入特定的 table。

-每个文件平均包含 180.000 条记录,我可以有多个文件。

-有些记录可以出现在多个文件中。

-如果每个列都匹配,则一条记录与另一条记录相同,换句话说,我不能简单地对特定字段执行检查。我在我的数据库中定义了一个约束,以确保满足此条件。

简而言之,我只想忽略 Oracle 在违反约束的情况下给我的约束异常。

记录不存在?-->插入

记录已经存在?--> 继续

这可以用 mybatis 实现吗?或者我可以在数据库级别完成一些事情吗?

我可以控制应用程序服务器和数据库,所以请告诉我完成此任务的最有效方法是什么(即使我想避免过多地依赖数据库...)

当然,我想避免在每次插入之前执行 select*...鉴于我正在处理的记录数量会破坏我的应用程序的性能

我不确定 JDBC,但至少在 OCI 中是可能的。通过批处理操作,您可以将向量作为绑定变量传递,还可以返回返回 ID 的向量以及错误代码的向量。

  • 您还可以在数据库服务器端将 MERGE 与自定义集合类型一起使用。类似于:

    merge into t

    using ( select * from TABLE(:var) v)

    on ( v.id = t.id )

    when not matched then insert ...

其中 :var 是 SQL 类型的绑定变量:TABLE OF <recordname> 单词 "TABLE" 是一个用于从绑定变量转换为 table.

的结构
  • 另一种选择是使用SQL错误登录子句:

    DBMS_ERRLOG.create_error_log (dml_table_name => 't');

    insert into t(...) values(...) log errors reject limit unlimited;

然后在加载后你将不得不截断错误记录 table err$_t;

与使用 sqlldr 相比,看起来任何解决方案都需要做很多工作。

使用IGNORE_ROW_ON_DUPKEY_INDEX提示:

insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX(table_name index_name) */
into table_name
select * ...

忽略有错误的错误table

insert 
into table_name
select * 
from selected_table
LOG ERRORS INTO SANJI.ERROR_LOG('some comment' ) 
                    REJECT LIMIT UNLIMITED;

错误table 模式是:

CREATE GLOBAL TEMPORARY  TABLE SANJI.ERROR_LOG (
        ora_err_number$         number,
        ora_err_mesg$           varchar2(2000),
        ora_err_rowid$          rowid,
        ora_err_optyp$          varchar2(2),
        ora_err_tag$            varchar2(2000),
        n1                      varchar2(128)
)
ON COMMIT PRESERVE ROWS;