对于典型的产品和发货数据库我正在探索运行触发器的最佳方式:
对于clatiry:订单表头将存储整体oder总数,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;
当更新订单行时,上述内容会导致突变错误。
答案 0 :(得分:3)
使用触发器实现完整性本身就存在问题,因为RDBMS读取一致性模式允许同时进行多次更改,无法看到彼此的结果。
更好的解决方案可能是避免对数据进行非规范化,并依赖于检测是否存在不完整的订单行来识别不完整的订单。由于这是少数情况,因此可以使用基于函数的索引对其进行优化:
create index my_index on orderline(case orderline_complete when 'NO' then orderid else null end)
这将仅对orderline_complete为“NO”的订单行的值进行索引,因此如果表中只有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;
答案 1 :(得分: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实例。希望这有帮助
答案 2 :(得分:0)