0

有人可以帮我纠正下面的触发器吗?我被分配了这个问题,但我的技术能力有限。

我的脚本遇到以下错误(ORA 4091):

处理标准 PO 编号:27179

...................................................

更新采购订单状态..

完成审批处理。

dist id 611294gl 金额 10000.88 bill_del_amount 0 l_amount 10000.88

发生了一些异常 **ORA-04091: 表 PO.PO_DISTRIBUTIONS_ALL 正在变异,

触发器/函数可能看不到它**

ORA-06512: 在 "APPS.XXAET_PO_DELIVER_TO_TRG",

第 22 行

ORA-01403: 未找到数据

ORA-04088: 执行触发器期间出错

'APPS.XXAET_PO_DELIVER

PL/SQL 过程成功完成。

SQL>

我设法在客户端机器中找到了自定义触发器,但经过研究,我无法确定 sql 有什么问题。请帮忙!

CREATE OR REPLACE TRIGGER apps.xxaet_po_deliver_to_trg
BEFORE INSERT OR UPDATE ON po_distributions_all
   FOR EACH ROW
DECLARE
   l_emp_name   VARCHAR2 (300);
   l_sqlcode    VARCHAR (30)   := SQLCODE;
   l_sqlerrm    VARCHAR (400)  := SUBSTR (SQLERRM, 1, 399);
   x_profile_value  VARCHAR (10) ;
BEGIN

x_profile_value := fnd_profile.value('ORG_ID');
  Select Ship_To_Location_ID
  INTO :NEW.Deliver_To_Location_Id
  from PO_LINE_LOCATIONS_ALL
  WHERE line_location_id = :NEW.line_location_id
  AND ORG_ID = x_profile_value
  ;

EXCEPTION
   WHEN OTHERS
   THEN
      NULL;

   UPDATE PO_DISTRIBUTIONS_ALL SET Deliver_To_Location_Id = :NEW.Deliver_To_Location_Id
   WHERE line_location_id = :NEW.line_location_id;

END;

/

太感谢了!肯尼斯。

4

4 回答 4

5

变异表错误意味着触发器代码可能不会在其拥有的表上发出 DML 语句。这是为了避免递归行为。解决方案非常简单。删除 UPDATE 语句。

这种说法背后的意图并不十分清楚。这很常见,因为 ORA-4091 错误通常表明设计不佳,例如数据模型标准化不足。我想这是你的情况。因此,解决问题需要比我们拥有更多的业务知识。

您的 SELECT 语句似乎也失败了(发布的错误堆栈有点混乱)。WHEN OTHERS THEN NULL;您正试图用臭名昭著的构造来抑制该语句的失败。这是德吸!立即将其删除。你需要知道你的代码失败了,以及为什么。如果 :NEW.Deliver_To_Location_Id 的人口是可选的,那么您不介意查找“失败”是否替换OTHERSNO_DATA_FOUND.

于 2009-10-23T04:48:23.480 回答
3

此问题的根本原因是使用触发器来执行除日志记录或其他与应用程序无关的任务之外的任何操作。以这种方式使用它们进行数据操作被广泛认为是非常糟糕的做法。

除此之外,还使用了 EXCEPTIONS 子句以静默地捕获错误并调用该更新。使用 WHEN OTHERS THEN NULL 是等待发生的悲剧。

所有不应该通过代码审查的糟糕的 PL/SQL 编程实践。

重构时间。

于 2009-10-23T07:45:03.437 回答
2

ORA-04091 的根本原因是异常处理——您不能对触发器附加到的表执行任何操作。在这种情况下 -PO_DISTRIBUTIONS_ALL

参考:ORA-04091 错误

我建议您将逻辑封装在存储过程中,并在 INSERT/UPDATE 语句之前在 INSERT/UPDATE 存储过程中调用它。

于 2009-10-23T04:48:00.890 回答
1

正如前面的答案中提到的,您会收到变异错误,因为您在触发器中更新同一个表,这是不允许的。

由于您使用的是“更新和插入之前”触发器,因此您需要做的就是将 :new.deliver_to_location_id 设置为正确的值。由于您已经在 select 语句中执行此操作,因此要修复触发器只需删除更新语句,因为您的 select 语句已经在更新记录字段。

作为一项改进,您可以用“when no_data_found”替换“when others”异常,这将帮助您抛出所有其他意外错误。

于 2009-10-28T07:57:15.917 回答