4

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

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

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

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

4 回答 4

1

我认为这不是一个好主意,因为在一个不止一个值发生变化的大表中,每个值都会产生更多开销。但这取决于您的应用程序。

此外,您应该考虑这种历史表的实用价值。您必须将很多行放在一起才能了解更改的值的上下文,并且它要求您编写另一个应用程序,该应用程序只为最终用户执行这种复杂的历史逻辑。对于数据库管理员来说,从历史中恢复值会很麻烦。

听起来可能有点刺耳,但这不是本意。我们店里一位经验丰富的程序员通过表格日志有一个类似的想法。他启动并运行它,但它吞噬了磁盘空间,就像没有明天一样。

想想你的历史表应该真正完成什么。

于 2008-11-11T07:42:16.717 回答
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
于 2008-11-14T01:40:39.060 回答
1

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

这使触发器更简单、更安全、更快,并且您可以有更多选择来实施后处理步骤。

于 2008-11-11T16:42:34.737 回答
1

我们在我们的 SQL Server 数据库上做了类似的事情,但是审计表是针对每个被审计的单独的表(一个中央表会很大,因为我们的数据库有很多千兆字节)

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

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

当您创建代码以将数据存储在历史记录表中时,如果需要,还可以创建代码以恢复数据。当需要恢复某些东西并且您面临来自高级管理层的压力要求现在完成它时,这将节省大量时间。

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

于 2008-11-11T19:08:27.517 回答