Oracle 触发器中需要列名、旧值和新值

Oracle 触发器中需要列名、旧值和新值,oracle,plsql,triggers,oracle11g,Oracle,Plsql,Triggers,Oracle11g,我们的要求是,如果表中的任何1个列名正在更新,我们需要在另一个表中插入列名,所以我编写了这段代码 CREATE OR REPLACE TRIGGER Test AFTER UPDATE ON XX_table FOR EACH Row BEGIN FOR C IN (SELECT column_name FROM User_Tab_Columns WHERE Upper(Table_Name) = 'XX_table_name' ORDER BY

我们的要求是,如果表中的任何1个列名正在更新,我们需要在另一个表中插入列名,所以我编写了这段代码

CREATE OR REPLACE TRIGGER Test AFTER
  UPDATE ON XX_table
   FOR EACH Row 
   BEGIN FOR C IN
    (SELECT column_name
    FROM User_Tab_Columns
    WHERE Upper(Table_Name) = 'XX_table_name'    ORDER BY column_id ASC) 
    LOOP 
    IF Updating (c.column_name) 
    THEN
    INSERT INTO Xx_Trigger_table    (Rt_Id ,Updated_Column ,updated_status) VALUES(:Old.Rt_Id,C.Column_Name,'Y');
    END IF;
END LOOP;
END;
现在客户端需要旧值以及XX_触发器_表中的新值。我无法写入

INSERT INTO Xx_Trigger_table    (Rt_Id ,Updated_Column ,updated_status,old_value, new_value) VALUES(:Old.Rt_Id,C.Column_Name,'Y',:old.c.column_name,:new.c.column_name);
请建议我在表中插入新值和旧值。
提前感谢。

如果您采用这种方法,就像@Alex Poole建议的那样,您必须包括所有要记录的列。请参阅本程序及其输出

CREATE OR REPLACE TRIGGER Test1 AFTER
  UPDATE ON TESTEMP
   FOR EACH Row 
   BEGIN FOR C IN
    (SELECT column_name
    FROM User_Tab_Columns
    WHERE Upper(Table_Name) = 'TESTEMP'    ORDER BY column_id ASC) 
    LOOP 
    IF Updating (c.column_name)  then
    IF (c.column_name='EMPNO') then
    INSERT INTO test_audit    (col_name,old_val,new_val,upd_stat) VALUES (C.column_name,:Old.empno,:New.empno,'Y');
    ELSIF
    (c.column_name='ENAME') then
    INSERT INTO test_audit    (col_name,old_val,new_val,upd_stat) VALUES (C.column_name,:Old.ENAME,:New.ENAME,'Y');
    ELSIF
    (c.column_name='MGR') then
    INSERT INTO test_audit    (col_name,old_val,new_val,upd_stat) VALUES (C.column_name,:Old.MGR,:New.MGR,'Y');
    END IF;
    END IF;
END LOOP;
END;



SQL> select * from testemp;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK           7902 17-DEC-80        800                    20
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30
      7566 JONES      MANAGER         7839 02-APR-81       2975                    20


SQL> select * from test_audit;

no rows selected

SQL> update testemp set empno=6677 , ename='JUPITER' where empno=1234;

1 row updated.

SQL> COMMIT;

Commit complete.

SQL> select * from test_audit;

COL_NAME   OLD_VAL    NEW_VAL    U
---------- ---------- ---------- -
EMPNO      1234       6677       Y
ENAME      SMITH      JUPITER    Y

这是一个奇怪的要求。为什么在审核表中需要
列名
?您只希望将修改后的行插入到带有
时间戳
列的审计表中。但出于其他事务目的,我们需要列名。如果你能帮助我,那就太好了。然后告诉客户这不是一个好的设计。对于审计,有许多更新的方法<代码>细粒度审计是一个很好的特性。否则,旧的触发方法应该按照我建议的方式实现。您需要一个审计表,所有列都与基表相似,还需要其他列,如id列作为PK,标识符列以了解它是否是
插入、更新或删除
,以及
时间戳
列。您不能像这样动态引用新/旧伪行中的列名(我很惊讶更新条款允许它,真的)。如果您决定使用此审核结构,则必须显式地单独测试每个列名,而不是在循环中测试,这意味着您列出了每个列名。如果您担心列的数量,则可以从数据字典中动态创建触发器代码。还请注意,
更新
意味着该列被引用,不一定是实际更改的值。作为替代方案,显示了一种使用更常见的审核表/触发器方法的方法,使用
unpivot
查看更改的值;您可以执行类似的操作,也许在视图中,以满足客户的要求,也许?Anu解决了上述代码i的问题如果我们对表进行任何更改,那么我们也必须对触发器进行更改。是的,但是表结构多久会更改一次?