执行触发器时出错。如何修改 select 语句?

Error during execution of trigger. How to rework select statement?

我对触发器比较陌生,如果这看起来不对劲,请原谅我。我正在创建一个触发器,用于检查用户帐户的上次付款日期,如果他们有一段时间没有付款,则将值设置为 0。我创建了我认为是正确的触发器,但在触发时出现错误 "error during execution of trigger"。据我了解,select 语句导致错误,因为它 selecting 正在更改的值。这是我的代码。

CREATE OR REPLACE TRIGGER t
  BEFORE 
   UPDATE OF LASTLOGINDATE
   ON USERS
   FOR EACH ROW
DECLARE
   USER_CHECK NUMBER;
   PAYMENTDATE_CHECK DATE;
   ISACTIVE_CHECK CHAR(1);

BEGIN 
   SELECT U.USERID, U.ISACTIVE, UP.PAYMENTDATE 
   INTO USER_CHECK, PAYMENTDATE_CHECK, ISACTIVE_CHECK
   FROM USERS U JOIN USERPAYMENTS UP ON U.USERID = UP.USERID
   WHERE UP.PAYMENTDATE < TRUNC(SYSDATE-60);

  IF ISACTIVE_CHECK = 1 THEN
    UPDATE USERS U
    SET ISACTIVE = 0
    WHERE U.USERID = USER_CHECK;

    INSERT INTO DEACTIVATEDUSERS
    VALUES(USER_CHECK,SYSDATE);

 END IF;


 END;

根据我的想法,由于 select 在 begin 语句中,它会 运行 在更新之前,在 if 运行s 之前,表不会发生任何变化通过触发器。我试过但在 select 变量前使用 :old 但这似乎不是正确的用法。

这是我正在尝试的更新语句。

UPDATE USERS 
SET LASTLOGINDATE = SYSDATE
WHERE USERID = 5;

一些问题:

  1. 您在触发器中执行的 select 将变量 isactive_check 设置为付款日期,反之亦然。那里有一个意外的开关,会对接下来有负面影响if;

  2. 同样的select应该return恰好一条记录,看样子不保证,因为你加入了tableuserpayments,这可能会为满足条件的选定用户支付数笔款项,或者根本 none。更改 select 以进行聚合。

  3. 如果用户有多个支付记录,条件可能对一个为真,但对另一个不为真。因此,如果您只对长时间未付款的用户感兴趣,则不应包括此类用户,即使他们有旧的付款记录。相反,您应该检查 all 记录是否满足条件。您可以使用 having 子句来做到这一点。

  4. 由于 table users 正在发生变化(更新触发器在 table 上),您不能对同一个 [=60= 执行所有操作],否则会导致一种僵局。这意味着您需要重新考虑触发器的用途。由于这是针对特定用户的更新,您实际上不需要检查整个 table,而只需检查正在更改的记录。为此,您可以使用特殊的 new 变量。

我建议改为 SQL:

SELECT   MAX(UP.PAYMENTDATE)
INTO     PAYMENTDATE_CHECK
FROM     USERPAYMENTS
WHERE    USERID = :NEW.USERID

然后继续检查:

IF :NEW.ISACTIVE = 1 AND PAYMENTDATE_CHECK < TRUNC(SYSDATE-60) THEN
    :NEW.ISACTIVE := 0;

    INSERT INTO DEACTIVATEDUSERS (USER_ID, DEACTIVATION_DATE)
    VALUES(USER_CHECK,SYSDATE);

END IF;

现在您已经避免在 table users 中执行任何操作,并通过 :new "record".

进行了检查和修改

此外,在 insert 语句中提及列名是一种很好的做法,我在上面的代码中已经这样做了(根据需要调整列名):

确保触发器已编译且未产生编译错误。