从包含审计跟踪的表中获取原始内容和修改内容

时间:2012-03-27 18:11:38

标签: sql postgresql audit-trail

我遇到了下面的表结构,我需要对它执行某种类型的查询。

  • id
  • 如first_name
  • last_name
  • 地址
  • 电子邮件
  • audit_parent_id
  • audit_entry_type
  • audit_change_date

最后三个字段用于审计跟踪。有一个约定:所有原始条目的值为“audit_parent_id”的值为“0”,“audit_entry_type”的值为“master”。所有修改的条目都具有audit_parent_id的父ID的值和“audit_entry_type”的值“modified”。

现在我想要做的是能够获得字段的原始值和修改后的值,并且我想用尽可能少的查询来实现。

有什么想法吗?谢谢。

2 个答案:

答案 0 :(得分:1)

假设一个简单的案例,当您想要获取ID为50的记录的最新地址值更改时,此查询符合您的需求。

select
    p.id,
    p.adress as original_address,
    (select p1.adress from persons p1 where p1.audit_parent_id = p.id order by audit_change_date desc limit 1) as latest_address
from
    persons p -- Assuming it's the table name
where
    p.id = 50

但是,假设即使address值在一次审核与另一次审核之间没有变化,它在字段中保持不变。

这是另一个例子,显示所有有地址变化的人:

select
    p.id,
    p.adress as original_address,
    (select p1.adress from persons p1 where p1.audit_parent_id = p.id order by audit_change_date desc limit 1) as latest_address
from
    persons p -- Assuming it's the table name
where
    p.audit_parent_id = 0
    and
    p.adress not like (select p1.adress from persons p1 where p1.audit_parent_id = p.id order by audit_change_date desc limit 1)

答案 1 :(得分:0)

这可以使用WITH RECURSIVE在现代Postgres中使用纯SQL来解决。

对于 PostgreSQL 8.3 ,这个plpgsql函数可以完成工作,同时它也是现代PostgreSQL的一个不错的解决方案。你想... ..

  

获取字段的原始值和修改值

演示选择first_name提交:

CREATE OR REPLACE FUNCTION f_get_org_val(integer
                                       , OUT first_name_curr text
                                       , OUT first_name_org  text) AS
$func$
DECLARE
     _parent_id int;
BEGIN
   SELECT INTO first_name_curr, first_name_org, _parent_id
               first_name,      first_name,     audit_parent_id
   FROM   tbl
   WHERE  id = $1;

   WHILE _parent_id <> 0
   LOOP
     SELECT INTO first_name_org, _parent_id
                 first_name,     audit_parent_id
     FROM   tbl
     WHERE  id = _parent_id;
   END LOOP;
END
$func$  LANGUAGE plpgsql;

COMMENT ON FUNCTION f_get_org_val(int) IS 'Get current and original values for id.
 $1 .. id';

呼叫:

SELECT * FROM f_get_org_val(123);

这假设所有树都有一个parent_id = 0的根节点。没有循环引用,或者你最终会得到一个无限循环。您可能希望添加计数器并在x次迭代后退出循环。