Oracle:在延迟约束失败的情况下继续插入

Posted

技术标签:

【中文标题】Oracle:在延迟约束失败的情况下继续插入【英文标题】:Oracle: Continuing Inserts with failing deferred constraints 【发布时间】:2018-02-27 14:41:24 【问题描述】:

抱歉这个问题太长了,但我希望它是完整的。

我的目标是创建一个流程,用 MS-SQL Server 创建的(和来自)MS-SQL Server 的数据填充 Oracle 11 数据库。 我想加载尽可能多的数据,并为未通过约束的记录创建错误报告,以便我们可以使用我们的数据测试新应用程序并改进我们的数据收集并重复此过程。

我有 NodeJS 脚本,它直接从 MS-SQL 表中读取(一次一个)并将 INSERT ... EXCEPTION/LOG ERRORS 语句发送到 Oracle 数据库。这似乎运作良好,直到最后。有些表有“可延迟约束”(例如,同一个表中的 parent_id),我无法忽略/报告,所以最后我总是以延迟约束和 0 个插入行的提交错误结束:(

注意:这个问题看起来很像Continuing Inserts in Oracle when exception is raised,但是它没有指定延迟约束或其他工具。

问题鉴于上下文(我不是真正的 Oracle 专家):

1) 是否有另一种方法来处理这些延迟约束,仍然插入有效数据并记录错误?

2) 是否有更好的工具来执行此迁移并报告当前数据问题?

【问题讨论】:

您可能会查看DML error logging,从而创建一个错误记录表作为dbms_errlog.create_error_log('name_of_table'),然后应用您的insert 和附加的log errors 子句。 @WilliamRobertson 我试过了(如问题中所述)。该文档指出,延迟约束没有被捕获。因此问题:) 啊,我错过了,对不起。 【参考方案1】:

嗯,听起来这些列可以延迟是有充分理由的,因为在插入所有行之前,您无法知道哪些行会违反约束。

我不确定这是否是最佳实践,但我会做的是:在将所有记录插入 my_table 之后,在提交之前,记录并删除所有无法通过约束检查的行,例如:

spool bad_rows.txt;
select * from my_table where parent_id not in (select id from my_table);
spool off;
delete from my_table where parent_id not in (select id from my_table);

从您的问题中我无法判断这是一次性数据迁移还是常规操作。如果您打算经常这样做,您可能会考虑使用creating an exception table 捕获违规行,然后在加载之前禁用约束,使用 EXCEPTIONS 子句重新启用它们(也许SET CONSTRAINTS ALL IMMEDIATE; 以检查违规行为),然后删除在发出提交之前,从表中冒犯的行(使用它们的 rowid)。我认为你应该能够很好地自动化它。

我做这种事情的频率不足以很好地回答你问题的第二部分。我可以说您的一些选项包括 (a) 使用 SQL*Loader 进行快速直接路径加载,它具有很好的错误处理能力,以及 (b) 在 MS SQL Server db 和 Oracle db 之间创建远程数据库链接, 并直接插入数据,以避免数据格式问题。希望其他人可以就良好的迁移工具提供更好的答案。

【讨论】:

SQL*Loader 可能是一个不错的选择。一切正常的都将被加载。不会出现所有错误,但您可以查看原因(在 LOG 文件中)和哪些行(在 BAD 文件中),然后采取适当的措施。 我确实选择了在提交之前手动处理可能失败的约束的解决方案,这感觉像是阻力最小的路径。在迁移中引入 SQLLoader 添加的另一个组件.. 将 SQLLoader 作为备份保留 :)

以上是关于Oracle:在延迟约束失败的情况下继续插入的主要内容,如果未能解决你的问题,请参考以下文章

oracle约束约束状态和设计习惯

如何在不违反主键约束的情况下插入具有循环引用的实体框架

Oracle - 在插入前触发检查约束

Oracle数据库约束问题

Oracle 空和唯一约束

如何在情节提要失败的情况下使用大量表格视图单元格和自动布局约束来布局复杂视图