Oracle Trigger自治事务缺失行

时间:2015-01-27 02:53:38

标签: oracle triggers

我有两个表:delivery_records和delivery_summary。我简化了表格来演示

select *
from delivery_records

FILTERLIST   PRICE_DATE   PRICE_VALUE
-------------------------------------
FL_1         1/1/2015     1
FL_1         1/1/2015     2
FL_1         1/1/2015     3
FL_2         1/1/2015     8
FL_2         1/1/2015     9

我在delivery_records上的每一行插入或更新后触发了一个触发器,它触发了过程summarize_records,以便在每次修改delivery_records表后立即更新delivery_summary表。

CREATE OR REPLACE TRIGGER SNAPSHOT_TRIG
  AFTER INSERT OR UPDATE ON DELIVERY_RECORDS FOR EACH ROW

Declare

    PRAGMA AUTONOMOUS_TRANSACTION;

BEGIN

    dbms_output.put_line('Starting trigger');

    SUMMARIZE_RECORDS(:new.filterlist, trunc(sysdate));

    COMMIT;

    dbms_output.put_line('Trigger ended');


EXCEPTION
    WHEN OTHERS THEN
            dbms_output.put_line('SQL Error: ' || SQLCODE || ' - ' || SUBSTR(SQLERRM, 1, 100));


END DELIV_SNAPSHOT_UPDATE;

过滤列表是一组相关的交付记录。 summarize_records存储过程通过在delivery_records表上运行select,然后将结果插入到delivery_summary表中,总结每个日期的每个筛选器列表的传递计数,我希望这些表可以产生以下结果:

select * from delivery_summary

FILTERLIST DATE       DELIVERY_COUNT
------------------------------------
FL_1       1/1/2015   3
FL_2       1/1/2015   2

这是按预期工作的,但似乎触发器缺少为每个筛选器列表插入的最后一条记录。几乎就像触发器没有发射一样。我做了一些研究,有人暗示自主交易无法看到当前交易的记录。这是我看到的表,除非我运行某种无操作更新以使触发器再次触发。

select * from delivery_summary

FILTERLIST DATE       DELIVERY_COUNT
------------------------------------
FL_1       1/1/2015   2
FL_2       1/1/2015   1

据我了解,作为“后”触发器,该行应该对我的摘要程序可见。我必须将程序设置为pragma autonomous,因为我正在选择正在触发的表。我知道这是禁忌,但它似乎是满足实时汇总表要求的唯一方法。

有没有更好的方法来实现这一目标?看起来这是触发器的完美用例。

2 个答案:

答案 0 :(得分:2)

在这种情况下,我认为使用AUTONOMOUS_TRANSACTION注释是错误的,因为:

  

在一次交易中,您正在更新delivery_records和   您将该事务标记为已分隔(通过使用pragma   AUTONOMOUS_TRANSACTION),您从中读取数据   delivery_records,in。

所以我更喜欢不使用AUTONOMOUS_TRANSACTION并在触发器中引入程序代码,然后直接计算所需的值并将其插入delivery_summary

答案 1 :(得分:1)

您可以使用语句触发器,即跳过FOR EACH ROW

在您的触发器中,您必须这样做(仅考虑更新):

UPDATE delivery_summary
SET (FILTERLIST, DATE, DELIVERY_COUNT) = 
    (SELECT FILTERLIST, DATE, COUNT(*) 
    FROM delivery_records
    GROUP BY FILTERLIST, DATE);

但是,更好的解决方案是将所有这些放入存储过程并调用此过程而不是使用触发器。