我可以将 :OLD 和 :NEW 伪记录复制到 Oracle 存储过程中吗?
我有一个 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 列而不是数十列的示例。
I have an AFTER INSERT OR UPDATE OR DELETE
trigger that I'm writing to store every record revision that occurs in a certain table, by copying the INSERT
and UPDATE
:NEW
values into a mirror table, and for DELETE
the :OLD
values.
I could un-clutter my code considerably by conditionally passing either the :NEW
or :OLD
record into a procedure which would then do the insert into my history table. Unfortunately I cannot seem to find a way to pass the entire :OLD
or :NEW
record.
Am I missing something or is there no way to avoid enumerating every :NEW
and :OLD
column as I invoke my insert procedure?
I want to do the following:
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;
But I'm stuck doing this:
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;
Okay, so it doesn't look like a big difference, but this is just an example with 3 columns rather than dozens.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
事实并非如此。你必须自己通过枚举来完成。
它不能/不自动工作的原因包括:
:old
和:new
是默认约定;您可以通过CREATE TRIGGER
的REFERENCING
子句将:old
和:new
引用命名为您想要的任何名称> 语句。您必须有一个类型的公共声明(通过
CREATE TYPE
或通过包声明)才能将其用作另一段代码的参数。触发代码是解释代码,而不是编译代码。
It isn't. You have to do it yourself through enumeration.
The reasons it can't/doesn't work automatically include:
the
:old
and:new
are default conventions; you can name the:old
and:new
references to be whatever you want through theREFERENCING
clause of theCREATE TRIGGER
statement.you'd have to have a public declaration of a type (through
CREATE TYPE
or through a package declaration) to be able to use it as an argument to another piece of code.trigger code is interpreted code, not compiled code.
我认为这是不可能的。 文档没有提到类似的内容。
这肯定会降低性能,但您可以尝试定义触发器
AFTER INSERT
和另一个BEFORE UPDATE OR DELETE
,并在触发器中执行类似以下操作:然后调用您的触发器使用该
rowtype_variable
的过程。I don't think it's possible like that. Documentation doesn't mention anything like that.
This would certainly cost performance, but you could try to define your trigger
AFTER INSERT
and another oneBEFORE UPDATE OR DELETE
, and in the trigger do something like:and then call your procedure with that
rowtype_variable
.使用SQL生成SQL;
然后复制并粘贴输出。
Use SQL to generate the SQL;
Then copy and paste output.
如果您使用AFTER触发器,您可以使用rowid作为参数来调用过程
如果您使用BEFORE触发器,您将得到ORA-04091 变异表,但是您的解决方案可以是(http://www.dba-oracle.com/t_avoiding_mutating_table_error.htm):
If you use AFTER trigger you can use rowid as parameter to call procedure
If you use BEFORE trigger you will get ORA-04091 mutating table, BUT you solution can be (http://www.dba-oracle.com/t_avoiding_mutating_table_error.htm):