什么数据类型是:OLD和:触发器中的新变量?

时间:2011-05-09 23:15:47

标签: sql oracle triggers

假设您在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参数的过程。

3 个答案:

答案 0 :(得分:4)

你做不到。 引用所有列(如SELECT *)通常是不好的做法,您应该指定所需的列。

答案 1 :(得分:2)

在文档中,您会发现:old和:new是列值,而不是行类型。因此,您必须手动构建行类型。

trigger ....
  l_row  mytable%rowtype;
begin
  l_row.column1 := :old.column1;
  l_row.column2 := :old.column2;
  ...

  archive_function(l_row);
end;

答案 2 :(得分:1)

从我可以确定的内容的定义:NEW和:OLD确实有点模糊。我看到它被称为对“伪记录”的引用。看起来,不是实际的rowtype,而是每个列都可以在rowtype中引用,Oracle会为每个单独的列设置一个引用,然后使用:NEW和:OLD引用它。但是,正如你所发现的那样:新的和:OLD似乎不能自己引用。

例如,here。 (是的,我知道,这是一个Java参考,但请参阅以下评论:OLD本身不是一个有效的参考。

我还发现这个注释SYS.DBMS_DEBUG包暗示:NEW /:OLD也不是有效的绑定。

  

- get_value和set_value现在支持绑定名称。绑定名称必须是        - 加上报价和大写。注意触发器绑定有        - 限定名称,即“:NEW”不是有效绑定,而“:NEW.CLMN”        - 有效。

this 建议您使用AFTER触发器吗?从您的示例来看,似乎没有对值进行任何验证(为了简单起见,您可能没有将它放到您的示例中)。

我试图设想一种方法来动态构建一个公共类型(在你的触发器中),使用all_tab_columns视图匹配你的表行类型,然后将所有值填入其中,但是不能完全包裹我的围绕可能会如何摆脱的细节...如果它甚至可以工作。它最终可能比记录历史记录所需的工作更多!