为什么会引发变异表错误?

时间:2020-04-09 18:28:52

标签: sql oracle

我正在尝试创建一个触发器,该触发器在删除表CLUBS中的行之前检查END_DATE列是否为空,如果该列为空,则代替删除该行,而不是删除该行,将其替换为sysdate,如果不为空,则将该行替换为不会被删除。

CREATE OR REPLACE TRIGGER TRANSFER_DATA 
BEFORE DELETE ON CLUBS
FOR EACH ROW 
  BEGIN
  IF :old.END_DATE IS NULL
  THEN UPDATE CLUBS SET END_DATE = SYSDATE;  
  ELSE
  RAISE_APPLICATION_ERROR(-20033, 'No se puede borrar');
  END IF;
END;

我已经尝试过此代码,但是会引发错误:

“表%s。%s正在变异,触发器/功能可能看不到它”

我如何使其起作用? 顺便说一下,我正在研究Oracle sqldeveloper

2 个答案:

答案 0 :(得分:1)

您需要创建一个视图和一个INSTEAD OF触发器:

create or replace view v_CLUBS as
SELECT * FROM CLUBS; -- perhaps add 'WHERE END_DATE IS NULL'

CREATE OR REPLACE TRIGGER TRANSFER_DATA 
   INSTEAD OF DELETE ON V_CLUBS
   FOR EACH ROW 
BEGIN
  IF :old.END_DATE IS NULL THEN 
     :new.end_date := sysdate;
  ELSE
     RAISE_APPLICATION_ERROR(-20033, 'No se puede borrar');
  END IF;
END;

答案 1 :(得分:0)

通过视图处理而不是触发是另一种有效的方法。看来您先前的尝试无法正确完成任务。一个简单的视图是完全可更新的(通常)。但是在这种情况下,您要拦截删除并将操作应用于基础表。假设CLUBS是您要处理的视图,而CLUBS_TBL是您想要的触发器的实际表:

-- create trigger to process deletes on the view
create or replace trigger del_clubs_isd
  instead of delete on clubs
begin 
  update clubs_tbl
     set end_date = sysdate
   where id = :old.id;
end del_clubs_isd; 

fiddle查看完整的脚本。
此外,如图所示,用户永远不需要知道球杆实际上并没有被删除,而只是被标记为以这种方式出现。