用于加入父子审计表的Postgres SQL

时间:2010-09-22 16:56:45

标签: sql postgresql reporting parent-child audit

我们正在使用"1 audit table for each monitored Table";但是,在我们的案例中,emp(PARENT)表中有一个子表emp_address,需要对其进行监控,因此我们有emp_auditemp_address_audit tables

postgres audit SQL:如何加入PARENT和CHILD表以进行报告。

/* Employee table */    
create table emp (
 emp_id integer primary key,
 empnum  integer,
 empname varchar(50),
 loginid varchar(20),
 updatetime timestamp
);

/* Address table */    
create table emp_addr (
 addr_id integer primary key,
 emp_id integer, -- references table emp
 line1 varchar(30),
 line2 varchar(30),
 loginid varchar(20),
 updatetime timestamp
);

/* Audit table for emp table */    
create table emp_audit (
 operation   character(1),
 emp_id integer,
 empnum  integer,
 empname varchar(50),
 loginid varchar(20),
 updatetime timestamp,
 txid bigint
);

/* Audit table for emp_addr table */    
create table emp_addr_audit (
 operation   character(1),
 addr_id integer,
 emp_id integer,
 line1 varchar(30),
 line2 varchar(30),
 loginid varchar(20),
 updatetime timestamp,
 txid bigint
);

我们使用hibernate(java)进行持久化,而hibernate只更新那些在更新操作中修改了列的表。鉴于此,我可能在emp_addr_audit表中为1个emp_audit表提供了多条(例如5条)记录。

每个事务(修改)报告需要1行。 该报告将包含以下列

empnum,empname,line1,line2,operation(insert / delete / update),loginid,updatetime

让我们考虑2个场景来理解需要什么:

  1. 在初始事务中,仅创建emp个属性。然后在单独的事务中,创建emp_addr中的相应行。所以,现在,我们在emp_audit表中有1行,在emp_addr_audit表中有1行。该报告将有2行(每个事务各一个)。
  2. empemp_addr属性都是在单个事务中创建的。这将确保emp_audit中有1行,emp_addr_audit中有1行。现在,报告将只有1行(因为两个表行都是在单个事务中创建的)。
  3. 哪种SQL会满足上述两种情况?

    更新
    场景:
    事务#1:我在emp和emp_addr中插入一行。这会在emp_audit和emp_addr_audit中产生一行。(INSERT)
    事务#2:我更新了上面的emp'属性。这导致emp_audit中的UPDATE行 事务#3:我更新了上面的emp_addr属性。这导致emp_addr_audit中的UPDATE行。

    我尝试了以下SQL#1,它按预期返回了3行;

    SQL#1

    SELECT emp.*, addr.*
     FROM  emp_audit emp 
     FULL OUTER JOIN emp_addr addr USING(emp_id, txid);
    

    但是,当我向SQL添加where子句时,它只返回2行。丢失的行是Transaction#3的结果,其中只有emp_addr表行已更新且emp表行未被触及。
    SQL#2

    SELECT emp.*, addr.*
     FROM  emp_audit emp 
            FULL OUTER JOIN emp_addr addr USING(emp_id, txid);
    WHERE  emp.empnum = 20;
    

    哪些SQL 仍然能够为3个交易获取3行,这样我仍然可以根据empnum过滤掉?

    谢谢,

1 个答案:

答案 0 :(得分:0)

首先在审计表中添加一个附加列txid bigint,然后修改执行审计的存储过程以调用txid_current()以将当前事务ID与审计记录一起存储。

CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $emp_audit$
    BEGIN
        --
        -- Create a row in emp_audit to reflect the operation performed on emp,
        -- make use of the special variable TG_OP to work out the operation.
        --
        IF (TG_OP = 'DELETE') THEN
            INSERT INTO emp_audit SELECT 'D', now(), user, txid_current(), OLD.*;
            RETURN OLD;
        ELSIF (TG_OP = 'UPDATE') THEN
            INSERT INTO emp_audit SELECT 'U', now(), user, txid_current(), NEW.*;
            RETURN NEW;
        ELSIF (TG_OP = 'INSERT') THEN
            INSERT INTO emp_audit SELECT 'I', now(), user, txid_current(), NEW.*;
            RETURN NEW;
        END IF;
        RETURN NULL; -- result is ignored since this is an AFTER trigger
    END;
$emp_audit$ LANGUAGE plpgsql;

然后,当您需要报告审计记录时,使用emp_id和txid在2个表之间执行外部联接,以便您可以在同一行中显示在同一事务中发生的2个单独插入。

SELECT emp_audit.*, emp_addr_audit.*
  FROM emp_audit
  FULL OUTER JOIN ON emp_audit.emp_id = emp_addr_audit.emp_id
                 AND emp_audit.txid = emp_addr_audit.txid;