我正在尝试创建一个触发器,该触发器在删除表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
答案 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查看完整的脚本。
此外,如图所示,用户永远不需要知道球杆实际上并没有被删除,而只是被标记为以这种方式出现。