创建DB2历史表触发器

时间:2008-11-10 23:58:35

标签: sql database db2 history triggers

我想创建一个历史表来跟踪DB2中许多表的字段更改。

我知道历史记录通常是复制整个表格的结构并给它一个后缀名称(例如user - > user_history)。然后,您可以使用一个非常简单的触发器将旧记录复制到更新的历史记录表中。

然而,对于我的应用程序,这会占用太多空间。每次字段更改时,将整个记录复制到另一个表格似乎不是一个好主意(至少对我来说)。所以我想我可以有一个通用的“历史”表来跟踪单个字段的变化:

CREATE TABLE history
(
    history_id LONG GENERATED ALWAYS AS IDENTITY,
    record_id INTEGER NOT NULL,
    table_name VARCHAR(32) NOT NULL,
    field_name VARCHAR(64) NOT NULL,
    field_value VARCHAR(1024),
    change_time TIMESTAMP,
    PRIMARY KEY (history_id)
);

好的,所以我要跟踪的每个表都有一个自动生成的id字段作为主键,它将被放入'record_id'字段。表中的最大VARCHAR大小为1024.显然,如果非VARCHAR字段发生更改,则必须先将其转换为VARCHAR,然后才能将记录插入历史表中。

现在,这可能是一种完全迟钝的做事方式(嘿,让我知道为什么会这样),但我认为这是跟踪需要很少提取并需要存储的变化的好方法很长一段时间。

无论如何,我需要帮助编写触发器以在更新时将记录添加到历史表中。让我们举一个假设的用户表:

CREATE TABLE user
(
   user_id INTEGER GENERATED ALWAYS AS IDENTITY,
   username VARCHAR(32) NOT NULL,
   first_name VARCHAR(64) NOT NULL,
   last_name VARCHAR(64) NOT NULL,
   email_address VARCHAR(256) NOT NULL
   PRIMARY KEY(user_id)
);

那么,任何人都可以帮助我更新用户表的触发器,将更改插入历史表吗?我的猜测是,需要使用一些过程SQL来遍历旧记录中的字段,将它们与新记录中的字段进行比较,如果它们不匹配,则在历史表中添加一个新条目。

如果可能的话,最好对每个表使用相同的触发器操作SQL,无论其字段是什么。

谢谢!

4 个答案:

答案 0 :(得分:1)

我认为这不是一个好主意,因为你会为一个大表生成更多的开销,其中一个大表会有多个值发生变化。但这取决于您的申请。

此外,您应该考虑这种历史表的实际价值。你必须将很多行放在一起,甚至可以看到更改后的值的上下文,并且它会重新命令您编写另一个为最终用户执行此复杂历史逻辑的应用程序。而对于DB-admin来说,恢复历史记录中的值会很麻烦。

它可能听起来有点刺耳,但这不是意图。我们店里经验丰富的程序员通过表日记表达了一个相似的想法。他得到了它并且正在运行,但它吃的磁盘空间就像没有明天一样。

想想你的历史表应该真正实现的目标。

答案 1 :(得分:1)

您是否考虑将此作为两个步骤进行?实现一个简单的触发器,记录整行的原始版本和更改版本。然后编写一个单独的程序,每天运行一次,以提取上面描述的更改字段。

这使得触发器更简单,更安全,更快速,并且您有更多选择来实现后处理步骤。

答案 2 :(得分:1)

我们在SQL Server数据库上做了类似的事情,但审计表是针对每个审计的单个表(一个中心表会很大,因为我们的数据库的大小是很多GB)

您需要做的一件事是确保您还记录了进行更改的人员。您还应该将旧值和新值一起记录(如果需要,可以更容易地将数据放回)和更改类型(插入,更新,删除)。你没有提到表中的记录删除,但是我们发现那些我们最常使用该表的东西。

我们使用动态SQl生成用于创建审计表的代码(通过使用存储系统信息的表),并且所有审计表具有完全相同的结构(使得更容易将数据取回)。

创建用于在历史记录表中存储数据的代码时,还需要创建代码以在需要时还原数据。当需要恢复某些东西时,这将节省大量的时间,而且你现在面临来自高级管理层的压力,要立即完成。

现在我不知道您是否计划从历史记录表中恢复数据,但是一旦您有一次,我可以保证管理层希望以这种方式使用它。

答案 3 :(得分:1)

CREATE TABLE HIST.TB_HISTORY ( 
    HIST_ID     BIGINT GENERATED ALWAYS AS IDENTITY (START WITH 0, INCREMENT BY 1, NO CACHE) NOT NULL,
    HIST_COLUMNNAME     VARCHAR(128) NOT NULL,
    HIST_OLDVALUE       VARCHAR(255),
    HIST_NEWVALUE       VARCHAR(255),
    HIST_CHANGEDDATE    TIMESTAMP NOT NULL
    PRIMARY KEY(HIST_SAFTYNO)
)
GO


CREATE TRIGGER COMMON.TG_BANKCODE AFTER
UPDATE OF FRD_BANKCODE ON COMMON.TB_MAINTENANCE
REFERENCING OLD AS oldcol NEW AS newcol FOR EACH ROW MODE DB2SQL
WHEN(COALESCE(newcol.FRD_BANKCODE,'#null#') <> COALESCE(oldcol.FRD_BANKCODE,'#null#'))
BEGIN ATOMIC

    CALL FB_CHECKING.SP_FRAUDHISTORY_ON_DATACHANGED(
                newcol.FRD_FRAUDID,
                'FRD_BANKCODE',
                oldcol.FRD_BANKCODE,
                newcol.FRD_BANKCODE,
                newcol.FRD_UPDATEDBY
    );--

    INSERT INTO FB_CHECKING.TB_FRAUDMAINHISTORY(        
        HIST_COLUMNNAME, 
        HIST_OLDVALUE, 
        HIST_NEWVALUE, 
        HIST_CHANGEDDATE