表正在变异,触发器/函数可能看不到它;需要后/行级查询
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] 正在变异,触发器/函数可能看不到它