我们正在使用"1 audit table for each monitored Table";但是,在我们的案例中,emp(PARENT)
表中有一个子表emp_address
,需要对其进行监控,因此我们有emp_audit
和emp_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个场景来理解需要什么:
emp
个属性。然后在单独的事务中,创建emp_addr
中的相应行。所以,现在,我们在emp_audit
表中有1行,在emp_addr_audit
表中有1行。该报告将有2行(每个事务各一个)。emp
和emp_addr
属性都是在单个事务中创建的。这将确保emp_audit
中有1行,emp_addr_audit
中有1行。现在,报告将只有1行(因为两个表行都是在单个事务中创建的)。哪种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过滤掉?
谢谢,
答案 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;