【问题标题】:Oracle trigger- instead of delete, update the roworacle触发器——更新行而不是delete
【发布时间】:2012-08-29 16:59:44
【问题描述】:

我如何编写 Oracle 触发器,而不是当用户删除某条记录时,删除实际上并没有发生,而是对这些行执行更新并将记录的状态设置为“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;

但是我遇到了变异表错误。这可能吗?

【问题讨论】:

    标签: sql oracle triggers


    【解决方案1】:

    首先,您编写的触发器会引发变异表错误。从技术上讲,您所要求的内容是不可能的,即删除不会删除而是更新,除非您在中间引发异常,这可能是一种丑陋的做法。我认为用户使用某种应用程序前端可以让他们使用删除按钮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;
    

    【讨论】:

    • 谢谢!我无权访问该应用程序。基本上,它是一个仓库管理系统,如果该产品没有任何移动,它将删除项目代码。如果有,它只会停用该项目。我希望它始终停用该项目。该界面使用的是 Oracle Forms,所以它非常难看,所以如果用户看到的是 oracle 错误,我并不担心,因为当前的应用程序分散在其中。
    • 如果您可以更改 oracle 表单代码以更改删除按钮功能,您可以这样做。或者,在 raise_application_error 中,而不是“无法删除项目”消息说“项目已删除/停用”。
    【解决方案2】:

    如果你真的需要一个触发器,更合乎逻辑的方法是创建一个视图,在视图上创建一个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. 创建一个删除前行级触发器,将:old.&lt;&lt;primary key&gt;&gt; 和所有其他:old 值插入到集合中
    4. 创建一个 after delete 语句级触发器,该触发器遍历集合,将行重新插入表中,并设置 item_stat 列。

    这将比instead of trigger 涉及更多的工作,因为您必须删除然后重新插入该行,并且它会涉及更多的移动部分,因此它会不那么优雅。但它会起作用。

    【讨论】:

    • 很遗憾我无法访问该应用程序,因此无法更改此设置
    • @Lock - 你是说这是第三方打包的应用程序吗?如果是这样,为什么您可以通过添加触发器来修改它?
    • 因为我有 sysdba 访问数据库
    • @Lock - 如果这是第三方打包应用程序,供应商通常不允许您首先向系统添加触发器。从技术上讲,您可能有权访问系统以添加触发器。但这样做会违反您的支持合同。如果您不在乎违反支持合同,我会返回创建视图。您可以重命名表,使用表名创建视图,并在视图上创建INSTEAD OF 触发器。这通常对应用程序是透明的。
    猜你喜欢
    • 2012-03-02
    • 1970-01-01
    • 2016-12-03
    • 2013-02-13
    • 2012-06-16
    • 2012-06-17
    • 1970-01-01
    • 1970-01-01
    • 2011-10-25
    相关资源
    最近更新 更多