表正在变异,触发器/功能可能看不到;需要后/行级别查询

时间:2019-05-07 01:45:16

标签: oracle plsql database-trigger

如何重写触发器以避免错误“ BB_BASKET正在变异,触发器/函数可能看不到它”

作业说明:创建一个名为BB_SALESUM_TRG的触发器,当确认订单或将BB_BASKET表中的ORDERPLACED列更新为1时,该触发器将相应地更新BB_SALES_SUM。

一直在寻找解决方案,同时不更改我的作业分配,这表明查询必须是AFTER触发器,因为在确认订单后必须更新库存。其他SO建议是将AFTER更改为BEFORE或INSERT,但是BEFORE触发器会在确认之前错误地更新清单,并且INSERT不能与行级触发器一起使用。完全避免触发的其他建议对于现实世界来说是好的,但对于专门针对触发的功课却不是。

语句级触发器可以避免此问题,但是我不能将WHEN子句与语句级触发器一起使用,我认为我需要WHEN或我的代码将不考虑数量来更新表。

添加一个实用的自主事务似乎并没有消除错误

家庭作业簿中的其他类似代码也可以将AFTER与游标中的SELECT语句一起使用没有问题,因此,我认为这不是游标中的SELECT语句使我感到悲伤。

CREATE TABLE BB_SALES_SUM (
product_id VARCHAR2(30) PRIMARY KEY,
total_sales NUMBER(8,2),
total_qty NUMBER(10),
OrderPlaced number(1)
);

Set ServerOutput On;
CREATE OR REPLACE TRIGGER bb_salessum_trg
AFTER UPDATE OF orderplaced ON bb_basket
FOR EACH ROW
WHEN(OLD.orderplaced <> 1 AND NEW.orderplaced = 1)
DECLARE
CURSOR basketitem_cur IS
   SELECT idbasket, total, quantity, orderplaced
   FROM bb_basket
   WHERE idbasket=:NEW.idbasket;
BEGIN
   FOR basketitem_rec in basketitem_cur LOOP
    UPDATE bb_sales_sum
    SET total_qty = basketitem_rec.quantity
    WHERE product_id = basketitem_rec.idbasket;
END LOOP;
END;
/

UPDATE bb_basket SET orderplaced = 1 WHERE idbasket = 14

1 个答案:

答案 0 :(得分:2)

您需要考虑问题的逻辑。 bb_sales_sum.total_qty是总数:即,它是所有已售商品的总和。您的触发器不会计算总数,因此(如果执行了)结果将是错误的:bb_sales_sum.total_qty将被设置为最后一个购物篮中商品的价值,而不是所售商品的总和。

仔细阅读问题,我们会发现它在正确的方向上有所帮助:

  

在确认订单或将BB_BASKET表中的ORDERPLACED列更新为1时,相应地更新BB_SALES_SUM。

触发器应该仅更新和,而不是覆盖它。让我们尝试一下。

注意:这看起来不对-product_id = :new.idbasket-但是您尚未发布完整的表格或示例数据集。另外,您还没有指定“确认订单” 的方式。因此,我将假设您的过滤逻辑是正确的。您可能需要对其进行调整。

CREATE OR REPLACE TRIGGER bb_salessum_trg
AFTER UPDATE OF orderplaced ON bb_basket
FOR EACH ROW
WHEN(OLD.orderplaced <> 1 AND NEW.orderplaced = 1)
BEGIN

    UPDATE bb_sales_sum
    SET total_qty = total_qty + :new.quantity
    WHERE product_id = :new.idbasket;

END;
/