在Oracle触发器中,我可以为rowtype变量分配new和old吗?

时间:2013-10-26 18:25:28

标签: oracle triggers

我的任务是实现几个触发器脚本,我从同事那里得到了一些工作的例子。在那些中,他们使用pl-sql条件进行更新/插入/删除,以及巨大的插入语句(在另一个表中)。除了值是以new还是old为前缀之外,这些insert语句不会有所不同。我以为我会很聪明,并尝试使用以下内容使我更紧凑:

DECLARE
  vRow SATURN.SPRCMNT%ROWTYPE;

BEGIN

  IF UPDATING THEN
    vRow := :NEW;
  ELSIF INSERTING THEN
    vRow := :NEW;
  ELSIF DELETING THEN
    vRow := :OLD;
  END IF;

  -- Not the real insert statement
  INSERT INTO blah 
    (columns)
    VALUES
    (vRow.somecolumns);

END;

我从编译系统中得到以下内容:

10/13  PLS-00049: bad bind variable 'NEW'
13/13  PLS-00049: bad bind variable 'NEW'
16/13  PLS-00049: bad bind variable 'OLD'

显然它不喜欢这个。有什么东西会实现我正在尝试的东西吗?是:新的和:旧的只是不是真正的rowtypes?看起来愚蠢的重复3次基本相同的代码,但我无法找到更好的方法。天啊,我想我已经读到触发器的大小也有一些硬限制。任何帮助表示赞赏。

[编辑]只是一个想法,是否有可能在DECODE()中以某种方式引用UPDATING / INSERTING关键字?

例如,如果我可以执行DECODE(SOMETHINGVAR,UPDATING,:NEW.column,DELETING,:OLD.column),那么我可以使用单个语句设置vRow中每列的值。

我想最好首先检查DELETING,然后使用其他两个的默认值。

这可能吗?

2 个答案:

答案 0 :(得分:4)

不,你不能。 :new:old是伪记录,而不是可以分配给局部变量的实际记录。如果您的表基于对象类型,则:new:old将是特定对象类型的实际实例,可以像任何其他对象一样传递。但是,为了使你的触发器更易于编写,不太可能在对象方面定义表格。

当然,您可以编写一个PL / SQL包,通过查询数据字典(即all_tab_columns以获取表中的列列表)来自动生成所需的触发器代码。动态SQL。根据您希望编写的触发器数量,这可能比编写和维护大量类似代码更容易。

答案 1 :(得分:3)

我决定回答这个问题,因为我多次听过这个问题,从未见过任何解决方案。

所以我的想法是让一个通用的“结构独立”触发器调用一些PL / SQL过程传递整个新旧行。

我使用了对象表。

create or replace type test_table_type as object(
  ... your attributes ....
);

create table test of test_table_type;

create or replace trigger trg_test_upd
before update on test
for each row
  l_new_row  test_table_type;
  l_old_row  test_table_type;
  l_row_id   raw(40000);
begin
  l_new_row := :new.sys_nc_rowinfo$; -- <-- this is your new row
  l_old_row := :old.sys_nc_rowinfo$; -- <-- this is your old row
  l_row_id :=  :old.sys_nc_oid$; -- <-- this your row logical ID (not rowid!!!). You can use it if you don't have primary key or it is composite.
  -- here you can do what ever you want with you old/new rows.
  ...
end;
/

我喜欢这种方法,因为它允许在基类型中定义公共属性并从此类型继承其他类型。因此,即使对于基于相同基类型的许多表,您也可以使用通用代码。