【问题标题】:Trigger could not be executed due to table mutating由于表变异,无法执行触发器
【发布时间】:2021-10-23 15:59:50
【问题描述】:

我想知道这个问题的问题是什么,当我执行我的存储过程时它一直向我显示这个错误。我的目标是在使用我的存储过程将数据更新到我的表之前,我想检查用户输入的触发器中的错误

SQL> exec PRC_PAY_TRIP(1031,2031,'Cash',200)
BEGIN PRC_PAY_TRIP(1031,2031,'Cash',200); END;

*
ERROR at line 1:
ORA-04091: table TEST.PAYMENT is mutating, trigger/function may not see it
ORA-06512: at "TEST.TRG_PAYMENT_VALIDATION", line 10
ORA-04088: error during execution of trigger 'TEST.TRG_PAYMENT_VALIDATION'
ORA-06512: at "TEST.PRC_PAY_TRIP", line 45
ORA-06512: at line 1

我去搜索问题,其中一个解决方案就是在触发器中将“之后”更改为“之前”

“付款更新前” --> 像这样

但还是不行

存储过程

CREATE OR REPLACE PROCEDURE PRC_PAY_TRIP(CUST_ID IN NUMBER,PAYMENT_ID IN NUMBER,PAYMENT_TYPE IN VARCHAR2,AMT_PAY IN NUMBER)AS


v_paymentstatus VARCHAR2(15) := 'Paid';
v_temppaymentid NUMBER(4) := PAYMENT_ID;
v_truenumber NUMBER(10);


no_null_on_custID EXCEPTION;
no_null_on_payID EXCEPTION;
invalid_paymentid EXCEPTION;
invalid_paymenttype EXCEPTION;
invalid_paymentamt EXCEPTION;


BEGIN

v_truenumber := v_temppaymentid-1000;


IF CUST_ID < 0
THEN
RAISE no_null_on_custID;
END IF;

IF PAYMENT_ID < 0
THEN
RAISE no_null_on_payID;
END IF;

IF CUST_ID ^= v_truenumber THEN
RAISE invalid_paymentid;
END IF;

IF PAYMENT_TYPE ^= 'Cash' AND PAYMENT_TYPE ^= 'E-Wallet' THEN
RAISE invalid_paymenttype;
END IF;

IF AMT_PAY < 0 THEN
RAISE invalid_paymentamt;
END IF;



UPDATE Payment
SET paymenttype = PAYMENT_TYPE,paymentdate = TO_CHAR(sysdate,'DD/MON/YYYY'), paymentstatus = v_paymentstatus
where paymentid = PAYMENT_ID;


EXCEPTION

WHEN no_null_on_custID then
DBMS_OUTPUT.PUT_LINE('Invalid Customer ID');

WHEN no_null_on_payID then
DBMS_OUTPUT.PUT_LINE('Invalid Payment ID');

WHEN invalid_paymenttype then
DBMS_OUTPUT.PUT_LINE('You can either choose Cash or E-Wallet only!');

WHEN invalid_paymentid then
DBMS_OUTPUT.PUT_LINE('Payment id is not yours, just add 1000 from your Customer ID and that will be your Payment ID');

WHEN invalid_paymentamt then
DBMS_OUTPUT.PUT_LINE('Amount pay cannot be negative value!');

END;
/

触发

CREATE OR REPLACE trigger trg_payment_validation
 before update on payment
 for each row

DECLARE

 v_paymentstatus payment.paymentstatus%type;
 v_customerid booking.customerid%type;
 v_paymentid payment.paymentid%type;
 v_paymentamt payment.paymentamount%type;

BEGIN 

select po.paymentstatus into v_paymentstatus
 from payment po
 where po.paymentid = :new.paymentid;


select po.paymentamount into v_paymentamt
 from payment po
where po.paymentid = :new.paymentid;

if SQL%FOUND then
    if v_paymentstatus = 'Paid' then
      RAISE_APPLICATION_ERROR(
        -20950,
        'You already paid for your trip, have a nice day'
      );
    elsif v_paymentamt < :old.paymentamount then
      RAISE_APPLICATION_ERROR(
        -20950,
        'Insufficient amount entered, pls pay the exact amount'
      );
    end if;
  end if;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    NULL;
END;
/

【问题讨论】:

标签: sql oracle stored-procedures plsql triggers


【解决方案1】:

如果您在更新时检查同一行中的数据,则不要使用SELECT 语句,而是检查:NEW:OLD 绑定变量:

CREATE OR REPLACE trigger trg_payment_validation
  before update on payment
  for each row
BEGIN 
  if :OLD.paymentstatus = 'Paid' then
    RAISE_APPLICATION_ERROR(
      -20950,
      'You already paid for your trip, have a nice day'
    );
  elsif :NEW.paymentamount < :old.paymentamount then
    RAISE_APPLICATION_ERROR(
      -20950,
      'Insufficient amount entered, pls pay the exact amount'
    );
  end if;
END;
/

【讨论】:

  • 嗨 MTO,您提供的代码已成功执行,但我认为我的错误命令让您感到困惑,因此我想更改此错误“您已经支付了旅行费用,祝您有美好的一天”对于此错误“您无法支付之前已支付的票价,祝您有美好的一天”
  • @TZEJIANTING 然后在应用程序中实现时更改文本。
  • 天哪,它有效,谢谢你!但我可以知道为什么不能引发第二个错误吗?我输入的付款金额低于付款表中所需的金额,但它没有引发该错误,实际上它立即继续该程序。这意味着即使输入的金额不足,它也会更新特定的行!请帮助我
  • 哪一栏告诉你需要的数量?我假设 paymentamount 是用户当前已支付的金额,您的触发器将检查他们是否没有以低于他们已经支付的金额更新行,但它不会检查支付的金额是否与应付总额。我不知道你的桌子,所以我不能回答它应该是什么;您需要提供更多信息或自行解决。
  • @TZEJIANTING 您没有更新过程中的PAYMENTAMOUNT,因此触发器中的第二个错误永远不会触发。
猜你喜欢
  • 2022-06-29
  • 1970-01-01
  • 2019-02-24
  • 2015-02-26
  • 2021-07-11
  • 2012-03-08
  • 2021-07-25
  • 2014-09-20
  • 1970-01-01
相关资源
最近更新 更多