如果行中的值设为NULL,我试图创建行级触发器以删除行。我的业务参数指出,如果将值设为null,则必须删除该行。另外,我不能使用全局变量。
BEGIN
IF :NEW.EXHIBIT_ID IS NULL THEN
DELETE SHOWING
WHERE EXHIBIT_ID = :OLD.EXHIBIT_ID;
END IF;
我收到以下错误:
ORA-04091: table ISA722.SHOWING is mutating, trigger/function may not see it
ORA-06512: at "ISA722.TRG_EXPAINT", line 7
ORA-04088: error during execution of trigger 'ISA722.TRG_EXPAINT'
执行此查询时:
UPDATE SHOWING
SET EXHIBIT_ID = NULL
WHERE PAINT_ID = 5104
答案 0 :(得分:0)
如前所述,这是一个糟糕的想法/设计。触发器是执行业务规则的非常差的方法。这些应在应用程序中或由应用程序调用的存储过程中更好的(IMO)实施。在这种情况下,这不仅是一个坏主意,而且无法按需实现。在触发器内,Oracle不允许访问触发了触发器的表。这就是变异所指示的。考虑在一周后尝试调试或解决问题。不过,可以通过创建视图并针对视图而不是表进行处理来实现这种无意义的操作。
-- setup
create table showing (exhibit_id integer, exhibit_name varchar2(50));
create view show as select * from showing;
-- trigger on VIEW
create or replace trigger show_iiur
instead of insert or update on show
for each row
begin
merge into showing
using (select :new.exhibit_id new_eid
, :old.exhibit_id old_eid
, :new.exhibit_name new_ename
from dual
) on (exhibit_id = old_eid)
when matched then
update set exhibit_name = new_ename
delete where new_eid is null
when not matched then
insert (exhibit_id, exhibit_name)
values (:new.exhibit_id, :new.exhibit_name);
end ;
-- test data
insert into show(exhibit_id, exhibit_name)
select 1,'abc' from dual union all
select 2,'def' from dual union all
select 3,'ghi' from dual;
-- 3 rows inserted
select * from show;
--- test
update show
set exhibit_name = 'XyZ'
where exhibit_id = 3;
-- 1 row updated
-- Now for the requested action. Turn the UPDATE into a DELETE
update show
set exhibit_id = null
where exhibit_name = 'def';
-- 1 row updated
select * from show;
-- table and view are the same (expect o rows)
select * from show MINUS select * from showing
UNION ALL
select * from showing MINUS select * from show;
同样,这是一个不好的选择,但是您可以这样做。但是,仅仅因为您可以做,并不意味着您应该做。否则您会对结果感到满意。祝你好运。
答案 1 :(得分:0)
您编写了一个触发器,该触发器在行更改之后或之前触发。这是在执行过程中。您不能在那一刻从同一张表中删除一行。
因此,您必须编写一个after语句触发器,而不是仅在整个语句运行后才触发。
create or replace trigger mytrigger
after update of exhibit_id on showing
begin
delete from showing where exhibit_id is null;
end mytrigger;
演示:https://dbfiddle.uk/?rdbms=oracle_18&fiddle=dd5ade700d49daf14f4cdc71aed48e17
答案 2 :(得分:0)
您可以做的是在同一张表中创建一个额外的列,如is_to_be_deleted,并执行以下操作:
UPDATE SHOWING
SET EXHIBIT_ID = NULL, is_to_be_deleted = 'Y'
WHERE PAINT_ID = 5104;
您可以使用此参数来实现不显示空详细信息的业务逻辑。
然后,您可以在该表上安排批量删除,以清理这些行(或将其存档)。 好处:您可以避免在该表上产生不必要的额外触发。
没人会建议您使用触发器来执行这种类型的删除,因为这样做很昂贵。