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

Posted

技术标签:

【中文标题】表正在变异,触发器/函数可能看不到它;需要后/行级查询【英文标题】:table is mutating, trigger/function may not see it; needs after/row level query 【发布时间】:2019-05-07 01:45:16 【问题描述】:

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

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

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

语句级触发器可能会避免该问题,但我不能将 WHEN 子句与语句级触发器一起使用,我认为我需要 WHEN 否则我的代码将更新表而不管数量多少。

添加一个pragma自治事务似乎并没有摆脱错误

我的作业书中的其他类似代码在游标中使用 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

【问题讨论】:

“其他完全避免触发器的建议适用于现实世界,但不适用于专门针对触发器的家庭作业。” 是的,这是家庭作业触发器的经典示例。 是的@APC 我不得不说的次数“我知道这没有意义,我永远不会在工作中这样做,但我需要这样做以完成作业" 让我每学期对 CS 专业的重视程度略低 【参考方案1】:

您需要考虑问题的逻辑。 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;
/

【讨论】:

以上是关于表正在变异,触发器/函数可能看不到它;需要后/行级查询的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 ORA-04091:表正在变异,触发器/函数可能看不到它?

错误触发器:表正在变异,触发器/函数可能看不到它

ORA-04091: 表 JOSEP.EMP 正在变异,触发器/函数可能看不到它

ORA-04091: 表 [blah] 正在变异,触发器/函数可能看不到它

Oracle - 在没有触发器的情况下更新表时出现“表正在变异,触发器/函数可能看不到它”错误

表正在变异,触发器/函数可能看不到它(阻止平均成绩降至 2.5 以下)