1

次のテーブル構造に遭遇し、特定のタイプのクエリを実行する必要があります。

  • ID
  • ファーストネーム
  • 苗字
  • 住所
  • Eメール
  • audit_parent_id
  • audit_entry_type
  • audit_change_date

最後の 3 つのフィールドは、監査証跡用です。すべての元のエントリは、「audit_parent_id」の値が「0」で、「audit_entry_type」の値が「master」であるという規則があります。変更されたすべてのエントリには、「audit_parent_id」の親 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 に答える