2012-02-14 195 views
1

当表中有列的任何列已更新时,我想插入一行到历史记录表中。PL SQL触发器在列更新时插入历史记录

我只是想捕捉列名,旧值和新值。

我希望这个触发器尽可能重复使用,因为我要在其他表上使用相同的概念。

我熟悉触发器以及如何捕获一列上的更新。我正在专门查找如何编写一个触发器,该记录将一条记录插入历史记录表中,用于任何列,该列在历史记录表的相应表中得到更新。

编辑1
我已经指出NOWHERE在我的职位,我在寻找源代码,这样任何人耻辱,downvotes我,认为我在找那个。你可以查看我以前的问题/答案,看看我不是在寻找“免费源代码”。

正如我在我原来的问题所述,我正在寻找如何来写这个。我已经检查了http://plsql-tutorial.com/plsql-triggers.htm,并且有一个代码块显示了如何在ONE列更新时写入触发器。我想,也许有人会知道如何为我提出的场景提供更通用的触发器。

+1

对。想知道我每小时收费多少? SO不是免费的编码服务。你试过什么了? – 2012-02-14 17:31:41

+0

@Adrian - 在这里寻找一个小方向...我的问题从来没有说明我正在寻找任何人为我写代码...... – 2012-02-14 17:36:14

+0

够公平的。问题在于你的问题听起来就像我正在阅读的Spec doc文件。你必须给我们一些东西。你有没有办法?你有没有研究过这是否可能?你研究过RDBMS(oracle)是否已经提供了这个功能吗? – 2012-02-14 17:39:48

回答

9

假设一个常规表格而不是一个对象表格,你没有很多选项。你触发必须是形式的东西

CREATE OR REPLACE TRIGGER trigger_name 
    AFTER UPDATE ON table_name 
    FOR EACH ROW 
BEGIN 
    IF(UPDATING('COLUMN1')) 
    THEN 
    INSERT INTO log_table(column_name, column_value) 
     VALUES('COLUMN1', :new.column1); 
    END IF; 

    IF(UPDATING('COLUMN2')) 
    THEN 
    INSERT INTO log_table(column_name, column_value) 
     VALUES('COLUMN2', :new.column2); 
    END IF; 

    <<repeat for all columns>> 
END; 

你可以获取COLUMN1COLUMN2,...从数据字典(USER_TAB_COLS),而不是COLUMN<<n>>字符串硬编码他们,但你还是要硬编码对:new伪记录中列的引用。

你可能会写一段代码,通过查询数据字典生成上述触发(USER_TAB_COLSALL_TAB_COLS最有可能的),建设有DDL语句的字符串,然后做一个EXECUTE IMMEDIATE执行DDL语句。您随后必须在任何时候将新列添加到任何表以重新创建该列的触发器时调用此脚本。编写和调试这种类型的DDL代码非常繁琐,但在技术上并不是特别具有挑战性。但很少有人值得这样做,因为有人不可避免地会添加一个新列并忘记重新运行该脚本,或者某人需要修改触发器以执行一些额外的工作,并且手动更新触发器比修改和测试生成的脚本更容易触发器。

但是,更普遍的是,我会质疑以这种方式存储数据的智慧。在历史记录表中为修改的每一行的每一列存储一行使得历史数据非常具有挑战性。如果有人想知道特定行在特定时间点处于什么状态,则必须将历史表N次加入其中,其中N是该时间点表中的列数。这会非常低效,很快就会让人们避免尝试使用历史数据,因为他们无法在合理的时间内对其做有用的事情,而不会让他们失望。使用具有相同的活动表格列的历史记录表(在跟踪日期等方面添加了一些内容)以及在每次更新行时在历史表中插入一行是比较有效的。这将消耗更多的空间,但它通常更容易使用。

而Oracle有多种方式来审计数据变更 - 您可以使用AUDIT DML,您可以使用细粒度审计(FGA),您可以使用Workspace Manager,也可以使用Oracle Total Recall。如果您正在寻找比编写自己的触发器代码更大的灵活性,我强烈建议您研究这些本质上更加自动化的其他技术,而不是尝试开发自己的架构。

+0

梦幻般的答案和方向 - 谢谢。 – 2012-02-14 18:01:36

+0

大答案像往常一样 – tbone 2012-02-14 18:07:46

4

您可能会将历史记录表设置为与主表格相同的+日期和类型字段。由于新值位于主表中,因此只需捕获旧值。 ,

create or replace trigger "MY_TRIGGER" 
before update or delete 
on MY_TABLE referencing new as new old as old 
for each row 
declare 
    l_dml_type varchar2(10); 
begin 
if (updating) then 
    l_dml_type := 'UPD'; 
else 
    l_dml_type := 'DEL'; 
end if; 

insert into MY_TABLE_HIST 
(
col1, 
col2, 
col3, 
dml_type, 
dml_date 
) 
values 
(
:old.col1, 
:old.col2, 
:old.col3, 
l_dml_type, 
sysdate 
); 
end; 
/
+0

+1 - 感谢这篇文章 - 我可能最终会朝着这个方向,因为它的简洁明了 – 2012-02-14 18:23:26

+3

我能得到Justin的点,然后;-) – tbone 2012-02-14 18:24:12

1

作为一个说明根据您的设计,如果空间是一个限制,您可以创建将跟踪的方式,你所追求的变化的看法,:

尝试这种(未经测试)并只显示当时的记录。

+1

这似乎是一个注释,下应张贴这样的题。在评论权限之前,您需要更多地参与社区以获得一些声誉。欢迎来到SO! – VKen 2012-10-10 19:21:00