有人可以帮我纠正下面的触发器吗?我被分配了这个问题,但我的技术技能有限。
我的脚本遇到以下错误(ORA 4091):
处理标准采购订单编号:27179
......................................
更新采购订单状态..
完成审批处理。
dist id 611294gl金额10000.88 bill_del_amount 0 l_amount 10000.88
发生了一些异常** ORA-04091:表PO.PO_DISTRIBUTIONS_ALL正在变异,
触发/功能可能看不到**
ORA-06512:at“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;
/
非常感谢你! 肯尼斯。
答案 0 :(得分:5)
变异表错误意味着触发器代码可能不会在其拥有的表上发出DML语句。这是为了避免递归行为。解决方案非常简单。删除UPDATE语句。
这一陈述背后的意图并不十分清楚。这很常见,因为ORA-4091错误通常表示设计不良,例如数据模型不够规范化。我想这是你的情况。因此,解决问题需要比我们更多的业务知识。
您的SELECT语句似乎也失败了(发布的错误堆栈有点混乱)。您试图用臭名昭着的WHEN OTHERS THEN NULL;
构造来抑制该语句的失败。这是Teh Suck!立即将其删除。您需要知道您的代码失败,以及原因。如果人口:NEW.Deliver_To_Location_Id是可选的,那么您不介意查找“失败”将OTHERS
替换为NO_DATA_FOUND
。
答案 1 :(得分:3)
此问题的根本原因是使用触发器执行除日志记录或其他非应用程序相关任务之外的任何操作。以这种方式将它们用于数据操作被广泛认为是非常糟糕的做法。
除此之外,还使用EXCEPTIONS子句静默捕获错误并调用该更新。然后使用其他等等,这是一个等待发生的悲剧。
所有可能永远不会通过代码审查的可怕的PL / SQL编程实践。
重构时间。
答案 2 :(得分:2)
ORA-04091的根本原因是EXCEPTION处理 - 您无法对附加触发器的表执行任何操作。在这种情况下 - PO_DISTRIBUTIONS_ALL
我建议您将逻辑封装在存储过程中,并在INSERT / UPDATE语句之前在INSERT / UPDATE存储过程中调用它。
答案 3 :(得分:1)
正如前面的答案中所提到的,由于你在触发器中更新同一个表是不允许的,因此你会发生变异错误。
由于您使用的是“更新和插入前”触发器,因此您需要设置:new.deliver_to_location_id,其值正确。由于您已在select语句中执行此操作,因此要修复触发器,只需删除update语句,因为您的select语句已在更新记录字段。
作为一项增强功能,您可以将“when when others”异常替换为“when no_data_found”,这将有助于您抛出所有其他意外错误。