我可以复制:OLD和:Oracle存储过程中的新伪记录吗?

时间:2010-02-25 20:20:53

标签: oracle stored-procedures plsql triggers

我正在写一个AFTER INSERT OR UPDATE OR DELETE触发器,通过将INSERTUPDATE :NEW值复制到某个表中来存储某个表中发生的每个记录修订版镜像表,DELETE :OLD值。

通过有条不紊地将:NEW:OLD记录传递到一个过程,然后插入到我的历史记录表中,我可以大大地解决我的代码问题。很遗憾,我似乎找不到通过整个:OLD:NEW记录的方法。

在我调用插入程序时,我是否遗漏了某些内容或者无法避免枚举每个:NEW:OLD列?

我想做以下事情:

DECLARE
  PROCEDURE LOCAL_INSERT(historyRecord in ACCT.ACCOUNTS%ROWTYPE) IS
  BEGIN
    INSERT INTO ACCT.ACCOUNTS_HISTORY (ID, NAME, DESCRIPTION, DATE) VALUES (historyRecord.ID, historyRecord.NAME, historyRecord.DESCRIPTION, SYSDATE);
  END;
BEGIN
  IF INSERTING OR UPDATING THEN
    LOCAL_INSERT(:NEW);
  ELSE --DELETING
    LOCAL_INSERT(:OLD);
  END IF;
END;

但我坚持这样做:

DECLARE
  PROCEDURE LOCAL_INSERT(id in ACCT.ACCOUNTS.ID%TYPE,
                         name in ACCT.ACCOUNTS.NAME%TYPE,
                         description in ACCT.ACCOUNTS.DESCRIPTION%TYPE) IS
  BEGIN
    INSERT INTO ACCT.ACCOUNTS_HISTORY (ID, NAME, DESCRIPTION, DATE) VALUES (id, name, description, SYSDATE);
  END;
BEGIN
  IF INSERTING OR UPDATING THEN
    LOCAL_INSERT(:NEW.ID, :NEW.NAME, :NEW.DESCRIPTION);
  ELSE --DELETING
    LOCAL_INSERT(:OLD.ID, :OLD.NAME, :OLD.DESCRIPTION);
  END IF;
END;

好的,所以看起来并没有什么大不同,但这只是一个有3列而不是数十列的例子。

4 个答案:

答案 0 :(得分:3)

不是。你必须通过枚举自己完成。

它不能/不能自动起作用的原因包括:

  • :old:new是默认约定;您可以通过:old声明的:new子句将REFERENCINGCREATE TRIGGER引用命名为您想要的任何内容。

  • 你必须有一个类型的公开声明(通过CREATE TYPE或通过包声明)才能将它用作另一段代码的参数。

  • 触发代码是解释代码,而不是编译代码。

答案 1 :(得分:1)

我不认为这样可能。 Documentation没有提到类似的事情。

这肯定会降低性能,但您可以尝试定义触发器AFTER INSERT和另一个BEFORE UPDATE OR DELETE,并在触发器中执行以下操作:

SELECT *
INTO rowtype_variable
FROM accounts
WHERE accounts.id = :NEW.id; -- :OLD.id for UPDATE and DELETE

然后使用rowtype_variable调用您的程序。

答案 2 :(得分:0)

使用SQL生成SQL;

select ' row_field.'||COLUMN_NAME||' := :new.'||COLUMN_NAME||';'  from 
    ALL_TAB_COLUMNS cols 
where 
    cols.TABLE_NAME = 'yourTableName'
order by cols.column_name.

然后复制并粘贴输出。

答案 3 :(得分:0)

如果您使用 AFTER 触发器,则可以使用rowid作为参数来调用过程

insert into t_hist
select * from t where rowid = r;

如果您使用 BEFORE 触发器,您将获得 ORA-04091 变异表 BUT < / strong>你的解决方案可以是(http://www.dba-oracle.com/t_avoiding_mutating_table_error.htm):

  • 不要使用触发器 - 避免变异表错误的最佳方法是不使用触发器。虽然面向对象的Oracle提供了与表相关联的“方法”,但大多数精明的PL / SQL开发人员都会避免使用触发器,除非绝对必要。
  • 使用“after”或“而不是”触发器 - 如果必须使用触发器,最好通过使用“after”触发器来避免变异表错误,以避免与变异表相关联的货币问题。例如,使用触发器“:在xxx上更新后”,原始更新已完成,表不会发生变异。
  • 重新设计触发器语法 - 霍尔博士对变异表错误有一些很好的说明,并提供了其他方法来避免使用行级和语句级触发器的组合来改变表。
  • 使用自治事务 - 您可以通过将触发器标记为自治事务来避免变异表错误,使其独立于调用该过程的表。