尝试根据我的触发器(SQL)中定义的条件删除行

时间:2019-06-27 17:43:15

标签: oracle plsql database-trigger

如果行中的值设为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

3 个答案:

答案 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;

您可以使用此参数来实现不显示空详细信息的业务逻辑。

然后,您可以在该表上安排批量删除,以清理这些行(或将其存档)。 好处:您可以避免在该表上产生不必要的额外触发。

没人会建议您使用触发器来执行这种类型的删除,因为这样做很昂贵。