如何编写Oracle触发器,而不是当用户删除某个记录时,删除实际上并没有发生,而是对这些行执行更新并将记录的状态设置为“D' D' ?
我试过了:
create or replace
trigger DELFOUR.T4M_ITEM_ONDELETE
before delete on M_ITEM_H
FOR EACH ROW
BEGIN
UPDATE
M_ITEM_H
SET
ITEM_STAT = 'D'
WHERE
CUST_CODE = 'TEST'
AND ITEM_CODE = 'GDAY'
;
raise_application_error(-20000,'Cannot delete item');
END;
但我正在改变表错误。这可能吗?
答案 0 :(得分:5)
如果你真的需要一个触发器,那么更合乎逻辑的方法是创建一个视图,在视图上创建一个INSEAD OF DELETE
触发器,并强制应用程序对视图而不是对基础发出删除表
CREATE VIEW vw_m_item_h
AS
SELECT *
FROM m_item_h;
CREATE OR REPLACE TRIGGER t4m_item_ondelete
INSTEAD OF DELETE ON vw_m_item_h
FOR EACH ROW
AS
BEGIN
UPDATE m_item_h
SET item_stat = 'D'
WHERE <<primary key>> = :old.<<primary key>>;
END;
更好的是,您可以省去触发器,创建一个应用程序可以调用的delete_item
过程,而不是发出DELETE
,该过程只需更新行以设置item_stat
}列而不是删除行。
如果你真的,真的,真的想要一个涉及表本身触发器的解决方案,你可以
m_item_h
表:old.<<primary key>>
和所有其他:old
值插入到集合中item_stat
列。这将涉及比instead of trigger
更多的工作,因为您必须删除然后重新插入行,这将涉及更多移动的部分,因此它将不那么优雅。但它会起作用。
答案 1 :(得分:3)
首先,您编写的触发器会抛出变异表错误。从技术上讲,你所要求的是不可能的,即删除不会删除而是更新,除非你在中间引发一个异常,这可能是一种丑陋的方式。我认为用户使用某种应用程序前端,使用删除按钮让他们delete
数据,因此您可以使用更新语句而不是delete
语句。
另一种选择是创建一个日志表,您可以在将记录从实际表中删除之前插入该记录,然后将日志表与实际表连接以检索已删除的记录。像 -
这样的东西 CRETAE TABLE M_ITEM_H_DEL_LOG as SELECT * FROM M_ITEM_H WHERE 1=2;
然后
create or replace
trigger DELFOUR.T4M_ITEM_ONDELETE
before delete on M_ITEM_H
FOR EACH ROW
BEGIN
INSERT INTO
M_ITEM_H_DEL_LOG
VALUES (:old.col1, :old.col2,.....) --col1, col2...are columns in M_ITEM_H
;
END;