在触发器中使用更新
using update in trigger
我有删除触发器
我想删除警察但是当我删除他时,所有其他他是他们老板的警察在他们的老板字段中都会有空
所以我使用了这段代码
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;
这是开始使用触发器时非常常见的问题。
除了通过 :NEW
和 :OLD
pseudo-records。这个想法是table处于不断变化的状态,所以它不能被触发器查询或修改..
处理此问题的典型方法是创建 两个 触发器:一个 row-level 触发器后跟一个 statement-level 触发器。
row-level 触发器注册包中的所有更改(包可以保存状态),而 statement-level 触发器跟进并根据行中发生的情况应用所有必要的修改--a statement-level触发器可以修改基础table.
以下是有关如何执行此操作的说明:Get rid of mutating table trigger errors with the compound trigger
在那篇文章中,Steven Feuerstein 不仅描述了问题的传统 package-based 解决方案,而且还提供了更现代的 compound-trigger-based 解决方案。
是的,要处理这种情况,您将需要以下触发器组合:
--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;
/
第一个触发器在每行之前,第二个在语句触发器之后。
干杯!!
我有删除触发器 我想删除警察但是当我删除他时,所有其他他是他们老板的警察在他们的老板字段中都会有空 所以我使用了这段代码
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;
这是开始使用触发器时非常常见的问题。
除了通过 :NEW
和 :OLD
pseudo-records。这个想法是table处于不断变化的状态,所以它不能被触发器查询或修改..
处理此问题的典型方法是创建 两个 触发器:一个 row-level 触发器后跟一个 statement-level 触发器。 row-level 触发器注册包中的所有更改(包可以保存状态),而 statement-level 触发器跟进并根据行中发生的情况应用所有必要的修改--a statement-level触发器可以修改基础table.
以下是有关如何执行此操作的说明:Get rid of mutating table trigger errors with the compound trigger
在那篇文章中,Steven Feuerstein 不仅描述了问题的传统 package-based 解决方案,而且还提供了更现代的 compound-trigger-based 解决方案。
是的,要处理这种情况,您将需要以下触发器组合:
--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;
/
第一个触发器在每行之前,第二个在语句触发器之后。
干杯!!