使用Oracle SET CONSTRAINTS ALL DEFERRED查找所有外键错误

时间:2008-11-10 19:21:43

标签: oracle

我正在使用:

set constraints all deferred;
(lots of deletes and inserts)
commit;

这可以按预期工作。如果存在任何损坏的关系,则提交失败并引发错误,列出其失败的一个FK。

用户修复有问题的数据并再次运行。然后点击另一个FK问题并重复该过程。

我真正想要的是一次性使用所有FK的列表,这会导致提交失败。

我当然可以通过select语句(每个FK一个选择)来编写一些东西以检查每个FK关系,但是使用延迟会话的好处在于这一切都是为我处理的。

3 个答案:

答案 0 :(得分:2)

立即回答对我来说很好。

从另一篇文章中取A,B,C示例:

SQL> create table a (id number primary key);

Table created.

SQL> create table b (id number primary key, a_id number, constraint fk_b_to_a foreign key (a_id) references a deferrable initially immediate);

Table created.

SQL> create table c (id number primary key, b_id number, constraint fk_c_to_b foreign key (b_id) references b deferrable initially immediate);

Table created.

SQL> insert into a values (1);

1 row created.

SQL> insert into b values (1,1);

1 row created.

SQL> insert into c values (1,1);

1 row created.

SQL> commit;

Commit complete.

我有一套一致的数据......我的出发点。 现在我开始一个会话来更新一些数据 - 这就是我在帖子中试图描述的内容。

SQL> set constraints all deferred;

Constraint set.

SQL> delete from a;

1 row deleted.

SQL> delete from b;

1 row deleted.

SQL> insert into b values (10,10);

1 row created.

SQL> set constraint fk_b_to_a immediate;
set constraint fk_b_to_a immediate
*
ERROR at line 1:
ORA-02291: integrity constraint (GW.FK_B_TO_A) violated - parent key not foun


SQL> set constraint fk_c_to_b immediate;
set constraint fk_c_to_b immediate
*
ERROR at line 1:
ORA-02291: integrity constraint (GW.FK_C_TO_B) violated - parent key not foun

告诉我关于破坏约束(C到B)和(B到A),而不回滚事务。这正是我想要的。

由于

答案 1 :(得分:1)

Oracle的错误机制过于原始,无法返回可能发生的所有错误的集合。我的意思是,这是一个很酷的想法,但想想如果你编写代码你必须做什么。您的标准错误处理需要被挫败。一旦遇到错误,你就不必立即返回错误,你必须继续以某种方式看看如果你抓到的第一个错误根本不是错误就可以继续。即使你做了所有这些,你仍然面临着你添加的修复第一个错误的行实际上可能导致第二个错误的可能性。

例如:

A是B的父级是C的父级。我推迟并插入C.我得到一个错误,即没有B记录父级。我推迟并添加B.现在我得到另一个错误,即没有A.

这当然是可能的,并且没有办法提前告知。

我认为您正在寻找服务器来做一些真正的责任。冒着mod -1的风险,你正在使用一种技术来发射一种叫做“喷射和祈祷”的自动武器 - 尽可能多地射击并希望你杀死目标。这种方法在这里不起作用。您禁用了RI并执行了一系列步骤,并希望在数据库“评分”您的DML时,所有RI最终都能正常工作。

我认为你必须编写代码。

答案 2 :(得分:1)

第一个选项,您可以查看DML error logging。这样就可以使约束处于活动状态,然后执行插入操作,错误行将进入错误表。您可以在那里找到它们,修复它们,重新插入行并从错误表中删除它们。

第二个选项是,不是尝试提交,而是尝试动态地重新启用每个延迟约束,捕获错误。您将查看一个PL / SQL过程,该过程向ALL_CONSTRAINTS查询可延迟的过程,然后执行EXECUTE IMMEDIATE以立即生成该约束。最后一位将在带有异常处理程序的块中,因此您可以捕获失败的那些,但继续。

就个人而言,我会选择(1)选项,因为你确实得到了失败的单个记录,而且你不必担心可延迟的约束,并且记住在这个脚本之后再次使它们立即生效,所以它不会以后打破一些东西。

我想内存中的某个地方Oracle必须维护一个列表,至少是那些失败的约束,如果不是实际的行。我非常有信心它不会在提交时重新扫描整个表集来检查所有约束。