我正在尝试使用触发器来避免在某些情况下删除表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:我接受了下面的解决方案,因为它是“政治上正确的”。由于一些“限制”,我无法使用它,最后找到了不同的解决方法。请参阅我单独发布的解决方案。
答案 0 :(得分:5)
在Orders和Product表之间使用外键而不是触发器。
答案 1 :(得分:0)
尝试使用AUTONOMOUS_TRANSACTIONS:
http://docs.oracle.com/cd/B19306_01/server.102/b14220/transact.htm#i7733
答案 2 :(得分:0)
您无法修复此错误,因为您选择的表格正处于您所在会话中DML操作的中间位置,因此无法确定您的查询的答案是在您创建时的答案。
然而,有一个稍微混乱但容易解决问题的方法:select * from products
的视图。 所以,这样的事情应该有效。
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)
通过删除Products
和Orders
之间的“链接”,最终解决了问题。该链接是名为ON DELETE CASCADE
的中间表的外键中的SuplProd
。通过从ON DELETE CASCADE
的fk中删除SuplProd
,表Orders
变为非变异。
为了利用删除ON DELETE CASCADE
,我只是在触发器的代码中添加了一行代码,就在END IF;
因此,从技术上讲,这种解决方法的工作方式是使必要的表不变异。