触发器中的 :OLD 和 :NEW 变量属于啥数据类型?
Posted
技术标签:
【中文标题】触发器中的 :OLD 和 :NEW 变量属于啥数据类型?【英文标题】:Of what data type are the :OLD and :NEW variables in a trigger?触发器中的 :OLD 和 :NEW 变量属于什么数据类型? 【发布时间】:2011-08-22 01:28:23 【问题描述】:假设您在MY_CUSTOMER_TABLE
上有一个触发器,并且它有一个声明为MY_CUSTOMER_TABLE%ROWTYPE
类型的变量。如何将 OLD
值分配给该变量?
CREATE TRIGGER CUSTOMER_BEFORE
BEFORE UPDATE ON MY_CUSTOMER_TABLE
FOR EACH ROW
DECLARE
old_version MY_CUSTOMER_TABLE%ROWTYPE;
BEGIN
old_version := :OLD; /* Causes a PLS-00049 bad bind variable 'OLD' */
old_version := OLD; /* Causes a PLS-00201 identifier 'OLD' must be declared */
END;
编辑:
澄清一下,这是因为我使用触发器将行从MY_CUSTOMER_TABLE
归档到MY_CUSTOMER_TABLE_HISTORY
。根据正在执行的操作(INSERT
、UPDATE
、DELETE
),我需要来自OLD
或NEW
的所有字段:
CREATE TRIGGER CUSTOMER_BEFORE
BEFORE UPDATE ON MY_CUSTOMER_TABLE
FOR EACH ROW
DECLARE
historical_record MY_CUSTOMER_TABLE_HISTORY%ROWTYPE;
PROCEDURE
copy
(
source_record MY_CUSTOMER_TABLE%ROWTYPE,
destination_record IN OUT MY_CUSTOMER_TABLE_HISTORY%ROWTYPE
)
BEGIN
destination_record.customer_id := source_record.customer_id;
destination_record.first_name := source_record.first_name;
destination_record.last_name := source_record.last_name;
destination_record.date_of_birth := source_record.date_of_birth;
END;
BEGIN
/* I didn't want to replicate the same assignment statements for
each of the two cases: */
CASE
WHEN INSERT OR UPDATING THEN
copy( source_record => :NEW, destination_record => historical_record );
WHEN DELETING THEN
copy( source_record => :OLD, destination_record => historical_record );
END CASE;
/* Some other assignments to historical_record fields... */
INSERT INTO MY_CUSTOMER_TABLE_HISTORY VALUES historical_record;
END;
在这种情况下,PL/SQL 不允许我将 :OLD
或 :NEW
传递给需要 MY_CUSTOMER_TABLE%ROWTYPE
参数的过程。
【问题讨论】:
这不起作用,您需要明确指定所有列...我也希望这样做。 Can I copy :OLD and :NEW pseudo-records in/to an Oracle stored procedure? 的可能重复项 【参考方案1】:你不能。 引用所有列(如 SELECT *)通常是不好的做法,您应该指定所需的列。
【讨论】:
感谢您的回答。 :) 我同意您关于将所有列称为不好的做法的评论。但是,就我而言,我明确需要 all 列(希望在我的编辑中演示)。您是否有任何文件的链接确认无法完成?【参考方案2】:在文档中,您会发现 :old 和 :new 是列值,而不是行类型。所以你必须手动构建你的行类型。
trigger ....
l_row mytable%rowtype;
begin
l_row.column1 := :old.column1;
l_row.column2 := :old.column2;
...
archive_function(l_row);
end;
【讨论】:
【参考方案3】:据我所知,:NEW 和 :OLD 的真正定义有点模糊。我已经看到它被称为对“伪记录”的引用。但是,看起来,Oracle 设置了对每个单独列的引用,而不是每个列在行类型中可引用的实际行类型,然后您可以使用 :NEW 和 :OLD 来引用它。但是,正如您所发现的, :NEW 和 :OLD 本身似乎不可引用。
例如,here。 (是的,我知道,这是一个 Java 参考,但请参阅关于 :OLD 本身不是有效参考的评论。
我还发现了这个注释 SYS.DBMS_DEBUG
包,它暗示 :NEW/:OLD 也不是有效的绑定。
-- get_value 和 set_value 现在支持绑定名称。绑定名称必须是 -- 加上引号并大写。请注意,触发器绑定具有 -- 限定名称,即 ":NEW" 不是有效绑定,而 ":NEW.CLMN" -- 有效。
this建议使用AFTER
触发器对您有用吗?从您的示例来看,似乎没有对值进行任何验证(意识到为简单起见,您可能没有将其放入示例中)。
我试图设想一种方法来动态(在您的触发器内)构造一个公共类型,该类型将使用 all_tab_columns 视图与您的表行类型匹配,然后将所有值填充到其中,但不能完全包装我的仔细研究这可能会如何摆脱的细节……如果它甚至可以工作的话。而且它最终可能比记录历史记录需要更多的工作!
【讨论】:
以上是关于触发器中的 :OLD 和 :NEW 变量属于啥数据类型?的主要内容,如果未能解决你的问题,请参考以下文章