用于联接父子审核表的Postgres SQL

用于联接父子审核表的Postgres SQL,sql,postgresql,reporting,parent-child,audit,Sql,Postgresql,Reporting,Parent Child,Audit,我们使用的是;然而,在我们的例子中,emp(父)table有一个子表emp\u address,它也需要监控,因此我们有emp\u audit和emp\u address\u audit tables postgres audit SQL:如何连接父表和子表以进行报告 /* Employee table */ create table emp ( emp_id integer primary key, empnum integer, empname varchar(50), l

我们使用的是;然而,在我们的例子中,
emp(父)
table有一个子表
emp\u address
,它也需要监控,因此我们有
emp\u audit
emp\u address\u audit tables

postgres audit SQL:如何连接父表和子表以进行报告

/* 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只更新那些列在更新操作中被修改的表。鉴于此,对于1个emp_审计表,我可能在emp_addr_审计表中有多个(比如5个)记录

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

empnum、empname、第1行、第2行、操作(插入/删除/更新)、loginid、updatetime

让我们考虑2种情况来理解需要什么:

  • 在初始事务中,仅创建
    emp
    属性。然后在单独的事务中,创建
    emp_addr
    中的对应行。现在,我们在
    emp\u audit
    表中有一行,在
    emp\u addr\u audit
    表中有一行。报告将有两行(每个事务一行)
  • emp
    emp\u addr
    属性都是在单个事务中创建的。这将确保在
    emp\u audit
    中有一行,在
    emp\u addr\u audit
    中有一行。现在,报告将只有一行(因为两个表行都是在一个事务中创建的)
  • 什么样的SQL能够满足上述两种情况

    更新
    场景:
    事务#1:我在emp和emp#u addr中插入一行。这将在emp_audit和emp_addr_audit中分别生成一行。(插入)
    事务#2:我更新上面的emp属性。这将导致emp_audit中的更新行。
    事务#3:我更新上述emp#u addr的属性。这将导致emp_addr_audit中的更新行。

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

    SQL#1

    但是,当我向SQL添加where子句时,它只返回2行。缺少的行是事务#3的结果,其中仅更新了emp#U addr表格行,未触及emp表格行。
    SQL#2

    什么样的SQL仍然能够为3个事务获取3行,这样我仍然可以基于empnum进行筛选


    谢谢,

    首先在审核表中添加一个附加列
    txid bigint
    ,然后修改执行审核的存储过程,以调用
    txid\u 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在两个表之间进行外部联接,以便您可以在一行上显示同一事务中发生的两个独立插入

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