1

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

  • ID
  • 地址
  • 电子邮件
  • audit_parent_id
  • audit_entry_type
  • audit_change_date

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

现在我想要做的是能够获得一个字段的原始值和修改后的值,我想用更少的查询来做到这一点。

有任何想法吗?谢谢你。

4

2 回答 2

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)
于 2012-03-27T18:40:36.080 回答
0

This can be solved with pure SQL in modern Postgres using WITH RECURSIVE.

For PostgreSQL 8.3, this plpgsql function does the job while it is also a decent solution for modern PostgreSQL. You want to ..

get the original value and the modified value for a field

The demo picks first_name as filed:

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

Call:

SELECT * FROM f_get_org_val(123);

This assumes that all trees have a root node with parent_id = 0. No circular references, or you will end up with an endless loop. You might want to add a counter and exit the loop after x iterations.

于 2012-03-27T21:00:13.780 回答