Oracle触发器 - 而不是删除,更新行

时间:2012-09-05 01:59:44

标签: sql oracle triggers

如何编写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;

但我正在改变表错误。这可能吗?

2 个答案:

答案 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 }列而不是删除行。

如果你真的,真的,真的想要一个涉及表本身触发器的解决方案,你可以

  1. 创建一个包含成员的包,该成员是映射到m_item_h
  2. 中数据的记录集合
  3. 创建清空此集合的删除前语句级别触发器
  4. 创建一个删除行前级触发器,将:old.<<primary key>>和所有其他:old值插入到集合中
  5. 创建一个after delete语句级触发器,遍历集合,将行重新插入表中,并设置item_stat列。
  6. 这将涉及比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;