删除时触发 我想删除警察,但是当我删除他时,所有其他警察(他是他们的老板)将在其老板字段中为空 所以我用了这段代码
create or replace trigger switch_boss
before delete
on policeman
for each row
declare
boss number;
begin
boss := :new.bossid;
if(:new.policemanid = :new.bossid)then
select policemanid into boss from
(select * from policeman
order by dbms_random.value)
where rownum =1;
end if;
update policeman
set bossid = boss
where bossid = :new.policemanid;
end switch_boss;
我遇到错误
ORA-04091: table SYSTEM.POLICEMAN is mutating, trigger/function may not see it
ORA-06512: at "SYSTEM.SWITCH_BOSS", line 13
ORA-04088: error during execution of trigger 'SYSTEM.SWITCH_BOSS'
有什么想法吗?
更新: 我用compund触发器触发了它的工作,但不是我想要的。 我想将已删除警察的上司设置为他所上司的上司。 问题是当我现在无法删除时,哪些警察已将已删除的警察作为上司。 我可以找到它们,因为它们在删除后的字段中为空,但它们可能属于其他已删除的警察。
这是我做的触发器:
create or replace trigger switch_boss
for delete
on policeman
compound trigger
after statement is
cursor c is select * from policeman where bossid is null for update;
boss number;
begin
for r in c loop
select policemanid into boss from
(select * from policeman order by dbms_random.value)
where rownum =1;
update policeman
set bossid = boss
where current of c;
end loop;
end after statement;
end switch_boss;
答案 0 :(得分:0)
使用触发器开始时,这是一个非常常见的问题。
除了通过POLICEMAN
和:NEW
伪记录外,Oracle不允许您的行级触发访问其基表(:OLD
)。这个想法是因为该表处于不断变化的状态,因此触发器无法查询或修改它。.
处理此问题的一种典型方法是创建两个 触发器:行级触发器,后跟语句级触发器。 行级触发器将所有更改记录在包中(包可以保留状态),而语句级触发器将跟进并根据行中发生的事情应用所有必要的修改-语句级触发器< em>可以修改基表。
以下是有关如何执行此操作的说明:Get rid of mutating table trigger errors with the compound trigger
在那篇文章中,Steven Feuerstein不仅描述了该问题的传统基于包的解决方案,而且还提供了一种更现代的基于复合触发的解决方案。
答案 1 :(得分:0)
是的,要处理这种情况,您将需要以下组合的触发器:
--First of all, You will need one package to hold the values:
CREATE OR REPLACE PACKAGE MY_VALUE_HOLDER AS
POLICEMANID NUMBER;
BOSS NUMBER;
END MY_VALUE_HOLDER;
/
-- Before each row trigger
CREATE OR REPLACE TRIGGER SWITCH_BOSS_ROW_TRG BEFORE
DELETE ON POLICEMAN
FOR EACH ROW
DECLARE
BOSS NUMBER;
BEGIN
BOSS := :OLD.BOSSID;
IF ( :OLD.POLICEMANID = :OLD.BOSSID ) THEN
SELECT
POLICEMANID
INTO BOSS
FROM
(
SELECT
*
FROM
POLICEMAN
ORDER BY
DBMS_RANDOM.VALUE
)
WHERE
ROWNUM = 1;
END IF;
MY_VALUE_HOLDER.POLICEMANID := :OLD.POLICEMANID;
MY_VALUE_HOLDER.BOSS := BOSS;
END SWITCH_BOSS_ROW_TRG;
/
--After statement trigger
CREATE OR REPLACE TRIGGER SWITCH_BOSS_ST_TRG AFTER
DELETE ON POLICEMAN
BEGIN
UPDATE POLICEMAN
SET
BOSSID = MY_VALUE_HOLDER.BOSS
WHERE
BOSSID = MY_VALUE_HOLDER.POLICEMANID;
END SWITCH_BOSS_ST_TRG;
/
第一个触发器在每行之前,第二个触发器在语句触发器之后。
干杯!