在触发前变异表

时间:2012-01-02 18:08:20

标签: oracle triggers

我正在尝试使用触发器来避免在某些情况下删除表Products中的行。代码如下

CREATE TRIGGER trgPreventProductRemoval
    BEFORE DELETE ON Products
    FOR EACH ROW

    BEGIN
        DECLARE
            l_custid INTEGER;
        BEGIN
            SELECT count(*) INTO l_custid FROM Orders WHERE product = :old.prodDescription ;

            IF l_custid > 0 THEN
                raise_application_error (-20100, 'You can not delete a product that has active orders!');
            END IF;
        END;
    END;

但是我收到错误:table ORDERS is mutating, trigger/function may not see it

我该如何解决?

EDIT-SOLUTION:我接受了下面的解决方案,因为它是“政治上正确的”。由于一些“限制”,我无法使用它,最后找到了不同的解决方法。请参阅我单独发布的解决方案。

4 个答案:

答案 0 :(得分:5)

在Orders和Product表之间使用外键而不是触发器。

答案 1 :(得分:0)

答案 2 :(得分:0)

您无法修复此错误,因为您选择的表格正处于您所在会话中DML操作的中间位置,因此无法确定您的查询的答案是在您创建时的答案。

然而,有一个稍微混乱但容易解决问题的方法:

  1. 创建表单select * from products的视图。
  2. 在视图而不是表格上编译触发器。
  3. 确保触发器执行您实际用于表格的DML操作(凌乱的部分)。
  4. 仅对视图而不是表执行DML操作。
  5. 所以,这样的事情应该有效。

    create or replace view v_products as select * from products;
    
    CREATE TRIGGER trgPreventProductRemoval
        BEFORE DELETE ON v_products
        FOR EACH ROW
    
        DECLARE
    
        l_custid INTEGER;
    
        BEGIN
    
           SELECT count(*) INTO l_custid 
             FROM Orders 
            WHERE product = :old.prodDescription;
    
            IF l_custid > 0 THEN
             raise_application_error (-20100, 'You can not delete a product that has active orders!');
            END IF;
    
           -- assumed, I don-t know the actual columns.
            delete from products where product = :new.product_id;
    
        END trgPreventProductRemoval;
    

答案 3 :(得分:0)

通过删除ProductsOrders之间的“链接”,最终解决了问题。该链接是名为ON DELETE CASCADE的中间表的外键中的SuplProd。通过从ON DELETE CASCADE的fk中删除SuplProd,表Orders变为非变异。

为了利用删除ON DELETE CASCADE,我只是在触发器的代码中添加了一行代码,就在END IF;

之后

因此,从技术上讲,这种解决方法的工作方式是使必要的表不变异。