2016-05-15 76 views
2

我是比较新的触发器,所以原谅我,如果这看起来不应该如此。我创建了一个触发器,用于检查上次付款日期的用户帐户,如果他们没有付款,则将值设置为0。我创建了我认为是正确的触发器,但当触发它时,我得到错误“触发器执行期间的错误”。据我所知,select语句在选择正在被更改的值时会导致错误。这是我的代码。执行触发器时出错。如何重新选择语句?

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; 

从我心想,既然选择是在开始的语句,它会运行一个更新之前,不会有任何改变有关的表,直到后,如果通过触发运行。我尝试过,但是在选择变量前面使用:old,但似乎没有正确的用法。

这里是我试图更新的声明。

UPDATE USERS 
SET LASTLOGINDATE = SYSDATE 
WHERE USERID = 5; 
+0

每个用户可以有多个用户付款记录吗? – trincot

+0

是的,可以。这是每次付款时的记录。 – rinaldo13531

回答

0

的一些问题:

  1. select您在触发做将变量isactive_check的付款日期,反之亦然。那里有一个意外开关,这将对下一个if产生负面影响;

  2. 同样select应返回一个记录,这由它的外观是没有保证的,因为你有桌子userpayments,这可能对满足条件的,或者根本就没有选择的用户数支付加盟。更改该select做一个聚合。

  3. 如果用户有多个付款记录,则该条件可能对一个记录为真,而对另一个记录则不适用。因此,如果您只对尚未付款的用户感兴趣,则不应将此用户包括在内,即使他们有旧的付款记录。相反,您应该检查所有记录是否符合条件。这可以通过having子句来完成。

  4. 由于表users正在发生变化(更新触发器在该表上),因此您无法对该表执行所有操作,否则会导致某种死锁。这意味着你需要重新思考触发的目的是什么。由于这是关于特定用户的更新,所以实际上不需要检查整个表格,而只需检查正在更改的记录。为此,您可以使用特殊的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; 

现在你已经避免了在表users做任何事情,并已取得了通过:new“记录”进行检查和修改。

此外,它是很好的做法,何况在insert语句中的列名,我在上面的代码做了(根据需要适应列名):

确保触发编译并不会产生编译错误。

+0

所以你说的是有道理的。如果我改变它的编译错误,“SQL语句被忽略”和“ORA-00936:缺少表达式”,那些似乎没有指向任何相关的东西。 – rinaldo13531

+0

对不起,我在那个SQL中有一个悬而未决的逗号。现在删除。 – trincot

+0

是的,我看到,它编译,但我仍然得到错误。*原因:触发器(或 此引用中引用的用户定义的plsql函数)试图查看(或修改)一个表是 在被解雇的陈述中修改。 *操作:重写触发器(或函数),使其不读取该表。 – rinaldo13531