【问题标题】:trigger after on insert, error table mutation upon inserting record插入后触发,插入记录时发生错误表突变
【发布时间】:2013-07-17 09:33:15
【问题描述】:

我创建了一个触发器,当向表Enrollment 插入新记录时,它将更新Payment 表(用于账单)。我的触发器如下:

CREATE OR REPLACE TRIGGER EnrollFee_trig
AFTER INSERT ON Enrollment
FOR EACH ROW

DECLARE
amount Payment.TotalPrice%TYPE;
id Payment.LearnerID%TYPE;

BEGIN
SELECT SUM(Price) into amount
FROM LearnerEnrollCourse_View
WHERE LearnerID = :NEW.LearnerID
AND Paid = 'N';

SELECT LearnerID into id
FROM Payment
WHERE LearnerID = :NEW.LearnerID
AND PaymentDate IS NULL;

IF SQL%FOUND THEN
UPDATE Payment 
SET TotalPrice = amount 
WHERE LearnerID = :new.LearnerID
    AND PaymentDate IS NULL;
ELSE  
INSERT INTO Payment VALUES
     (PaymentID_Seq.nextval, :new.LearnerID, '', amount);  
END IF;

END;
/

可以成功创建触发器。但是在向Enrollment 表中插入新记录时,会出现错误提示“表ENROLLMENT 正在变异,触发器/函数可能看不到它”。我想更具体地了解导致此问题的原因以及如何解决。

【问题讨论】:

    标签: sql oracle triggers relational-database sqlplus


    【解决方案1】:

    当我们尝试从行级触发器代码中引用查询中的触发表时,会发生变异表异常。查看更多here

    在这种情况下,我怀疑(虽然我不知道,因为没有 LearnerEnrollCourse_View 的定义)问题是由以下语句引起的:-

    SELECT SUM(Price) into amount
    FROM LearnerEnrollCourse_View
    WHERE LearnerID = :NEW.LearnerID
    AND Paid = 'N';
    

    如果 LearnerEnrollCourse_view 视图引用 Enrollment 表,您将收到 mutating table 错误。有很多方法可以解决它,将触发器代码移动到语句级触发器并将数据保存在包变量中是一种解决方法,但总的来说,我认为使用触发器不是最好的方法,触发器越多你有,你就越有可能遇到这个问题和其他问题。相反,我将有一个用于注册表的 api 包,并将触发代码移动到那里。

    很好地讨论了触发器here

    【讨论】:

    • 是的,视图确实引用了Enrollment 表。在语句级触发器中,如何获取新插入的列数据如:NEW.LearnerID?
    • 可以使用包变量来存储行触发器中的数据,然后在语句级触发器中引用包变量。但是,我不建议这样做。
    猜你喜欢
    • 2016-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-06
    • 1970-01-01
    相关资源
    最近更新 更多