我正在写一个AFTER INSERT OR UPDATE OR DELETE
触发器,通过将INSERT
和UPDATE
: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列而不是数十列的例子。
答案 0 :(得分:3)
不是。你必须通过枚举自己完成。
它不能/不能自动起作用的原因包括:
:old
和:new
是默认约定;您可以通过:old
声明的:new
子句将REFERENCING
和CREATE 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):