【发布时间】:2021-10-13 04:25:23
【问题描述】:
这是我的问题的情况:
我们公司正在销售一个带有数据输入的 BI 应用程序,它基本上为值发生变化的每一行运行一个更新。
- 我正在尝试为我们的用户创建一个功能来创建预算。
- 在我的表中,我有 12 个用于帐户过帐的字段(借方 - 贷方 该月)和 12 用于每个月的帐户余额。
- 我希望如果我的用户在过帐上进行数据输入,那么几个月的余额 得到相应更新,如果我的用户在 余额,过帐会相应调整
- 不能同时在过账和余额上进行数据输入(2 个单独的 工作表)
我在 SQL Server 中使用触发器检查过帐是否已更改,重新计算余额,反之亦然。
我尝试在 Oracle 中做同样的事情(我们必须同时支持两者,而且我不是 Oracle 专家)但我不断收到 Mutation 错误,我想这是因为它陷入了一个循环,其中: 过帐 -> 更新余额 -> 更新过帐 -> 等等。
我环顾四周并尝试了不同的解决方案,例如在触发器内更新之前禁用触发器并在使用匿名事务之后重新启用它,但更新无法解决。
我尝试在触发器中添加一个更新为 1 的标志,并仅在它的新值为 0 时触发触发器(之后另一个触发器将其重置为 0),但它似乎不起作用.
我尝试使用临时表记录哪些行发生了更改,以查看它是 Posting 更改还是 Balance 更改,然后在没有 FOR EACH ROW 的情况下运行更新,但它仍然导致问题。
有人有什么想法吗? 代码是这样的:
CREATE OR REPLACE TRIGGER "QA_BUD_V8"."UPDATE_BUDGET_VALUES"
AFTER UPDATE OF
B_POSTING01,B_POSTING02,B_POSTING03,B_POSTING04,B_POSTING05,B_POSTING06,B_POSTING07,B_POSTING08,B_POSTING09,B_POSTING10,B_POSTING11,B_POSTING12
,B_OPENINGBALANCE
,B_ENDINGBALANCE01,B_ENDINGBALANCE02,B_ENDINGBALANCE03,B_ENDINGBALANCE04,B_ENDINGBALANCE05,B_ENDINGBALANCE06,B_ENDINGBALANCE07,B_ENDINGBALANCE08,B_ENDINGBALANCE09,B_ENDINGBALANCE10,B_ENDINGBALANCE11,B_ENDINGBALANCE12
ON "QA_BUD_V8".UDM_BUDGET_INWORK
FOR EACH ROW
BEGIN
IF (:OLD.B_OPENINGBALANCE <> :NEW.B_OPENINGBALANCE
OR :OLD.B_POSTING01 <> :NEW.B_POSTING01
OR :OLD.B_POSTING02 <> :NEW.B_POSTING02
OR :OLD.B_POSTING03 <> :NEW.B_POSTING03
OR :OLD.B_POSTING04 <> :NEW.B_POSTING04
OR :OLD.B_POSTING05 <> :NEW.B_POSTING05
OR :OLD.B_POSTING06 <> :NEW.B_POSTING06
OR :OLD.B_POSTING07 <> :NEW.B_POSTING07
OR :OLD.B_POSTING08 <> :NEW.B_POSTING08
OR :OLD.B_POSTING09 <> :NEW.B_POSTING09
OR :OLD.B_POSTING10 <> :NEW.B_POSTING10
OR :OLD.B_POSTING11 <> :NEW.B_POSTING11
OR :OLD.B_POSTING12 <> :NEW.B_POSTING12) THEN
[UPDATE Balances with Postings]
ELSIF (:OLD.B_ENDINGBALANCE01 <> :NEW.B_ENDINGBALANCE01
OR :OLD.B_ENDINGBALANCE02 <> :NEW.B_ENDINGBALANCE02
OR :OLD.B_ENDINGBALANCE03 <> :NEW.B_ENDINGBALANCE03
OR :OLD.B_ENDINGBALANCE04 <> :NEW.B_ENDINGBALANCE04
OR :OLD.B_ENDINGBALANCE05 <> :NEW.B_ENDINGBALANCE05
OR :OLD.B_ENDINGBALANCE06 <> :NEW.B_ENDINGBALANCE06
OR :OLD.B_ENDINGBALANCE07 <> :NEW.B_ENDINGBALANCE07
OR :OLD.B_ENDINGBALANCE08 <> :NEW.B_ENDINGBALANCE08
OR :OLD.B_ENDINGBALANCE09 <> :NEW.B_ENDINGBALANCE09
OR :OLD.B_ENDINGBALANCE10 <> :NEW.B_ENDINGBALANCE10
OR :OLD.B_ENDINGBALANCE11 <> :NEW.B_ENDINGBALANCE11
OR :OLD.B_ENDINGBALANCE12 <> :NEW.B_ENDINGBALANCE12) THEN
[UPDATE Postings with Balances]
END IF;
END;
触发器中是否有一种方法可以在不触发触发器的情况下进行更新或退出导致突变的循环? 不幸的是,我只能控制代码的某些 SQL 部分。我没有在应用程序中明确设置用于预算的模块,而是尝试利用应用程序中的数据输入功能来进行预算,因此我可以做的事情受到限制。
【问题讨论】:
-
我过去在这种情况下所做的是创建一个包含一个名为
TRIGGER_SUPPRESSION之类的公共变量的包。当触发器触发时,它做的第一件事就是检查变量中的值。如果它是真的,它什么也不做。如果为假,则将其设置为真并进行更新。然后在更新完成后将其重置为 false(确保您还放置了一个 EXCEPTION 块来重置它,这样您就不会永远锁定该功能)。另一个触发器应该查看相同的变量并实现相同的逻辑。 -
我尝试了您的建议,但由于某些原因,我无法访问触发器内的包变量,它总是告诉我必须声明它。我试图将它放在一个表中,只有当它为空时,我的第一个触发器才会将 P 或 B 插入到该全局变量表中,然后我基于该表运行更新,并在更新后删除该行,但我仍然收到突变错误。能不能给个更详细的答案或者给个链接?
-
找到我自己的答案,感谢您的帮助