【问题标题】: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。根据正在执行的操作(INSERTUPDATEDELETE),我需要来自OLDNEW 的所有字段:

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 参数的过程。

【问题讨论】:

标签: sql oracle triggers


【解决方案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 视图与您的表行类型匹配,然后将所有值填充到其中,但不能完全包装我的仔细研究这可能会如何摆脱的细节……如果它甚至可以工作的话。而且它最终可能比记录历史记录需要更多的工作!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-21
      • 2020-11-10
      • 2018-11-30
      • 2014-02-15
      • 2018-12-19
      • 2013-11-05
      • 2021-04-27
      • 1970-01-01
      相关资源
      最近更新 更多