0

我有一个表,我试图根据给定的值进行插入/更新。但是插入不适用于这个特定的表,但它适用于脚本运行的以前的表。

为了测试这个问题,我在 oracle 的 sqldeveloper 中放入了一些匿名块,它根据是否存在密钥进行插入或更新。更新似乎工作正常,但在插入新行时,没有插入任何内容。

如果我有这张桌子:

COFFEE_ID       TEA_ID        NAME      
    11             100        combo 1
    12             101        combo 2
    13             102        combo 3

这样做不会插入任何内容,而是会转到下一个匿名块:

   begin
      insert into COFFEE_TEA(COFFEE_ID, TEA_ID, NAME) values (14, 103, 'combo 4');
   exception when dup_val_on_index then 
      update ....
   end;

    ....

我怀疑这与这张桌子上的触发器有关。它是一种BEFORE EACH ROW触发器类型,它会将数据插入到其他表中。触发器中没有异常处理,所以我猜它一定会失败但不报告(运行脚本时不会出现在 sqldeveloper 中)。

我的两个问题是,

当触发器运行时,如果它试图插入到另一个表的 ID 已经存在会发生什么?看起来它默默地失败了?

我应该如何最好地解决这个问题?我不确定我是否可以更改触发器代码本身,但是否有可能在我的匿名块中捕获错误(假设它实际上是导致问题的触发器)。如果是这样,如果它静默失败,我怎么知道要捕获什么异常?


我删除了 sqldeveloper 中的异常,它告诉我违反了唯一约束。即通过触发器插入另一个表的数据是原因。

4

2 回答 2

3

您的附加信息告诉我们您的触发器正在抛出 ORA-00001,这是一个唯一密钥违规。这是 DUP_VAL_ON_INDEX 异常处理的错误。所以看起来你的异常处理程序应该处理 COFFEE_TEA 上的关键违规行为,它也在吞噬你的触发器中的异常。凌乱。

有两种可能的解决方案。一种是在触发代码中进行适当的错误处理。另一种是使用 MERGE 进行数据加载例程。

我总是更喜欢 MERGE 作为执行 upserts 的机制,因为我不喜欢使用异常来处理合法的预期状态。 了解更多

理想情况下,您应该两者都做。触发器应该是独立的代码:在与其表交互的例程上施加未处理的异常会破坏封装。

于 2012-10-03T14:46:53.877 回答
0

触发器不会修改表上的 DML 进程。COFFEE_TEA删除异常块,如果是表,则插入将成功或失败并出现错误。

换句话说,如果COFFEE_TEA是表,以下脚本将永远不会输出 0:

BEGIN
   INSERT INTO coffee_tea(COFFEE_ID, TEA_ID, NAME) values (14, 103, 'combo 4');
   dbms_output.put_line(sql%rowcount);
END;
于 2012-10-02T16:15:52.060 回答