3

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

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'

显然它不喜欢这样。有什么可以实现我正在尝试的东西吗?:new 和 :old 不是真正的行类型吗?将本质上相同的代码重复 3 次似乎很愚蠢,但我想不出更好的方法。地狱,我想我读到触发器的大小也有一些硬性限制。任何帮助表示赞赏。

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

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

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

这可能吗?

4

2 回答 2

4

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

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

于 2013-10-27T06:37:33.960 回答
4

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

所以这个想法是有一个通用的“结构独立”触发器调用一些传递整个新旧行的 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;
/

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

于 2014-10-13T15:21:10.220 回答