2012-03-27 11 views
1

次の表構造を見つけました。特定の種類のクエリを実行する必要があります。監査証跡を持つテーブルから元の内容と変更された内容を取得する

  • ID
  • first_nameの
  • last_nameの
  • アドレス
  • メール
  • は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"の値は "modified"です。

これで、元の値と変更された値を取得できます。フィールドには、私は可能性少ないクエリでこれを作りたい。

任意のアイデア?ありがとう。簡単な場合を想定し

+0

実際にデータベースに変更を加えることができないため、アプリケーションでバグ修正を行う必要があります。 – Psyche

+0

つまり、すべてのテーブルに最後の3つのフィールドがありますか? – everton

+0

ほとんどすべてのテーブル、はい。 – Psyche

答えて

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 

しかし、これは、ある監査と他の監査の間で値が変更されない場合でも、フィールド内で同じままであることを前提としています。

はここでアドレスの変更を持っていたすべての人を示す、別の例です:

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) 
+0

を選んで、変更されたバージョンのために、「audit_parent_id」の値は、常に前の変更のないID、元のバージョンのIDになりますしてください。 – Psyche

+0

ああ、それは今や理にかなっている。正確に何を追跡する必要がありますか? – everton

+1

純粋なSQLはWITH RECURSIVEを持っていますので、再帰的なクエリを行うことができます(もちろん、十分に最近のPostgreSQLが与えられている)。 –

0

これはWITH RECURSIVEを使用して、現代のPostgresに純粋なSQLで解決することができます。

PostgreSQL 8.3の場合、このplpgsql関数は最新のPostgreSQL用のまともなソリューションですが、ジョブを実行します。

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); 
あなたは...

が提出されたとして、元の値とデモがfirst_nameを選び、フィールド

ための修正値を取得したいです

これは、すべてのツリーにというルートノードがあることを前提としています210。循環参照がないか、無限ループになります。 xを反復した後にカウンタを追加してループを終了したい場合があります。

関連する問題