【问题标题】:Need Column name , old value and new value in Trigger触发器中需要列名、旧值和新值
【发布时间】:2015-06-26 18:41:50
【问题描述】:

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

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_Trigger_Table 中的旧值和新值。我无法写入

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);

请建议我在表格中插入新旧值。 提前致谢。

【问题讨论】:

  • 这是一个奇怪的要求。为什么在审计表中需要 column name?您希望将修改后的行插入到带有 timestamp 列的审计表中。
  • 是的,这是客户的奇怪要求。但是我们需要列名用于其他交易目的。如果你能帮助我,那就太好了。
  • 然后告诉客户什么不是好的设计。对于审计,有许多更新的方法。 Fine Grained Auditing 是一个很好的功能。否则,应该按照我建议的方式实施旧的触发方法。您需要一个审计表,其所有列都与基表类似,还有其他列,例如 id 列作为 PK,标识符列以了解它是否是 insert, update or delete,以及 timestamp 栏目。
  • 您不能像那样动态地引用新/旧伪行中的列名(我很惊讶更新子句允许它,真的)。如果您确定要使用此审计结构,那么您将必须明确且单独地测试每个列名,而不是循环测试,这意味着您列出每个列名。如果您担心列数,可以从数据字典中动态创建触发代码。另请注意,updating 表示该列被引用,不一定是该值实际发生了变化。
  • 作为替代方案,this old answer 显示了一种使用更常见的审计表/触发器方法的方法,unpivot 可以查看更改的值;你可以做一些类似的事情,也许是为了满足客户的要求,也许?

标签: oracle plsql triggers oracle11g


【解决方案1】:

如果您遵循这种方法,就像@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

【讨论】:

  • Anudeepks 上面代码的问题是,如果我们对表进行任何更改,那么我们也必须在触发器中进行更改。
  • 是的,但是表结构多久更改一次?
猜你喜欢
  • 2021-04-24
  • 1970-01-01
  • 2021-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多