1

我在包含审计日志的表上创建了一个触发器。插入新条目时,我想逐列将新记录与表中的最新现有记录(匹配 ID)进行比较。如果一列的值发生了变化,我想在另一个表中执行插入语句。我创建了以下 PL SQL 过程:

CREATE OR REPLACE
TRIGGER PROJECT_BASELINE_ATTR_AUD_BI BEFORE INSERT
ON PROJECT_BASELINE_ATTR_AUD 
FOR EACH ROW
DECLARE 
  tab_name constant varchar2(32) := 'PROJECT_BASELINE_ATTR_AUD';
  col_name varchar2(32);
  v_latest_row PROJECT_BASELINE_ATTR_AUD%rowtype;
BEGIN
  -- get the record to compare with
  EXECUTE IMMEDIATE 'select * from  '||tab_name||
            ' where rev = (select max(rev) from '||tab_name||' where id = '|| :new.ID ||')' into v_latest_row;
FOR x IN (SELECT DISTINCT(COLUMN_NAME) FROM ALL_TAB_COLUMNS WHERE TABLE_NAME = upper(tab_name)) 
  LOOP
  BEGIN
    col_name := x.column_name;
    -- do insert if the values are unequal
    -- IF :new.col_name <> v_latest_row.col_name
    --   INSERT INTO AUD_CHANGE_LOG VALUES (AUD_CHANGE_LOG_ID_SEQ.nextVal, :new.ID, :new.REV, tab_name, col_name);
  END;
  END LOOP;
END;

我知道我可以用真实的列名来实现它,例如

IF :new.FOO <> v_latest_row.FOO
IF :new.BAR <> v_latest_row.BAR
...

但这将在很长的情况下结束。有任何想法吗?

4

3 回答 3

1

无法动态引用触发器的新旧值。

您可以开发一个系统,为您需要的每个表结构动态定义触发器,但无论如何这都是一项艰巨的工作。

我做了类似的事情,这不是你可以在几天内完成的事情。

于 2012-07-16T18:53:26.920 回答
0

我同意 Alessandro 的观点,即您不能动态引用列名。您必须手动为每个插入。就个人而言,我认为这种复杂的逻辑最好在编译过程中完成,而不是直接在触发器中完成。费尔斯坦同意。

因此,我会将新表行传递给存储过程,并通过将新列值放在 WHERE 子句中,让它完成将每一列与审计表进行比较的繁重工作。

于 2012-07-20T16:54:29.660 回答
-1

是的。仅当操作发生在同一个表上时才会发生变异表错误。

对于看起来像审计表触发器的东西,我不认为有一种方法可以解决我所知道的逐列比较。

于 2012-07-16T14:25:04.407 回答