1

对于典型的产品和运输数据库,我正在探索运行触发器的最佳方法:

  1. 当订单行设置为“完成”时,将运行触发器:
  2. 查找该订单的任何其他订单行。
  3. 如果该订单的所有其他订单行也是“完成”
  4. 更新订单标题表以完成。

对于 clatiry:订单标题表将存储整个订单总额,而 orderLines 表存储订单的每个产品。

到目前为止,触发器是这样编写的:

CREATE OR REPLACE TRIGGER orderComplete
after update ON orderline
for each row
WHEN (new.orderline_fulfilled = 'Y')
DECLARE count NUMBER := 5;
ordersNotDone NUMBER;
BEGIN

SELECT COUNT(Orderline_fulfilled) INTO ordersNotDone
FROM orderHeader
JOIN orderline ON
orderHeader.Order_id = orderLine.Orderline_order
WHERE Order_id = :old.orderline_order
AND orderline_fulfilled = 'Y';

IF ordersNotDone = 0
THEN
UPDATE orderHeader
SET completed = SYSDATE
    WHERE orderId = :old.orderline_order;
ENDIF;

END;

在更新订单行时,上述情况会导致突变错误。

4

3 回答 3

3

使用触发器强制执行完整性本质上是有问题的,因为 RDBMS 读取一致性模式允许同时进行多个更改,而这些更改无法看到彼此的结果。

更好的解决方案可能是避免对数据进行非规范化,并依靠检测不完整订单行的存在来识别不完整订单。由于这将是少数情况,因此可以使用基于函数的索引进行优化,如下所示:

create index my_index on orderline(case orderline_complete when 'NO' then orderid else null end)

这将仅索引 orderline_complete 为“NO”的 orderline 的值,因此如果表中只有 100 个这样的行,则索引将仅包含 100 个条目。

识别不完整的订单只需使用查询对非常紧凑的索引进行完整或快速完整索引扫描:

select distinct
  case orderline_complete when 'NO' then orderid else null end orderid
from
  orderline
where
  case orderline_complete when 'NO' then orderid else null end is not null;
于 2012-04-28T21:51:13.140 回答
0

最简单的答案是使用稍微不同类型的触发器,它不是在更新行之后而是在更新表之后触发。这不会受到这个问题的影响。

所以做类似的事情:

CREATE or REPLACE TRIGGER trigger_name
AFTER INSERT ON orderline --note no for each row
BEGIN

  --loop over all orders which contain no unfulfilled orders
  FOR lrec IN (SELECT order_id FROM orderline group by order_id where not exists (select 1 from orderline where orderline_fulfilled = 'Y'))
  LOOP
    -- do stuff to order id because this are complete
  END LOOP;
END;

所以在这里我们可能已经在插入上完成了多个订单,所以触发器需要处理这个问题。抱歉,我没有可以在家玩的 oracle 实例。希望这可以帮助

于 2012-04-29T22:10:35.353 回答
0

如果您使用的是 11g,请检查复合触发器,例如:http ://www.toadworld.com/KNOWLEDGE/KnowledgeXpertforOracle/tabid/648/TopicID/TRGC1/Default.aspx

于 2012-05-02T06:53:52.273 回答