2010-09-22 6 views
1

Nous utilisons un "1 audit table for each monitored Table"; Cependant, dans notre cas emp(PARENT) table a une table enfant emp_address qui doit également être surveillé, nous avons donc emp_audit et emp_address_audit tables.Postgres SQL pour joindre des tables d'audit parent-enfant

postgres audit SQL: comment joindre des tables PARENT et CHILD à des fins de génération de rapports.

/* 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 
); 

Nous utilisons Mise en veille prolongée (java) pour les mises à jour et la persistance mise en veille prolongée uniquement les tables dont les colonnes ont été modifiées dans l'opération de mise à jour. Compte tenu de cela, je pourrais avoir plusieurs (disons, 5) enregistrements dans la table emp_addr_audit pour 1 table emp_audit.

Le rapport nécessite 1 ligne pour chaque transaction (modification). Le rapport aura les colonnes suivantes

empnum, empname, ligne1, line2, opération (insertion/suppression/mise à jour), loginid, updatetime

Considérons 2 scénarios pour comprendre ce qui est nécessaire:

  1. Dans la transaction initiale, seuls les attributs emp sont créés. Ensuite, dans une transaction distincte, la ligne correspondante dans emp_addr est créée. Donc, maintenant, nous avons 1 ligne dans le tableau emp_audit et 1 ligne dans le tableau emp_addr_audit. Le rapport comportera 2 lignes (une pour chaque transaction). Les attributs emp et emp_addr sont créés en une seule transaction. Cela garantira qu'il y a 1 ligne dans emp_audit et 1 ligne dans emp_addr_audit. Maintenant, le rapport aura SEULEMENT 1 ligne (puisque les deux lignes de table ont été créées en une seule transaction).

Quel SQL satisfera les deux scénarios ci-dessus?

MISE À JOUR
Scénario:
Transaction # 1: insérer une ligne dans les deux emp et emp_addr. Cela se traduit par une ligne dans emp_audit et emp_addr_audit. (INSERT)
Transaction # 2: Je mets à jour l'attribut emp 'ci-dessus. Cela entraîne une ligne UPDATE dans emp_audit. Transaction # 3: Je mets à jour l'attribut emp_addr ci-dessus. Cela entraîne une ligne UPDATE dans emp_addr_audit.

J'ai essayé le SQL n ° 1 suivant et il a renvoyé 3 lignes comme prévu;

SQL # 1

SELECT emp.*, addr.* 
FROM emp_audit emp 
FULL OUTER JOIN emp_addr addr USING(emp_id, txid); 

Cependant, quand j'ai ajouté une clause where à SQL, il ne retourne que 2 lignes. La ligne manquante était le résultat de la transaction n ° 3, où seule la ligne de table emp_addr était mise à jour et la ligne de table emp était intacte.
SQL # 2

SELECT emp.*, addr.* 
FROM emp_audit emp 
     FULL OUTER JOIN emp_addr addr USING(emp_id, txid); 
WHERE emp.empnum = 20; 

Qu'est-ce que SQL Taisez-vous en mesure de me faire 3 lignes pour les 3 opérations afin que je puisse filtrer encore sur la base de empnum?

Merci,

Répondre

0

Tout d'abord ajouter une colonne txid bigint aux tables d'audit supplémentaires, modifiez le proc stockée qui effectue la vérification d'appeler txid_current() pour stocker l'ID de transaction en cours avec le dossier de vérification.

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; 

Puis, quand vous avez besoin de rendre compte des enregistrements d'audit faire une jointure externe entre les 2 tables en utilisant le emp_id et la txid afin que vous puissiez présenter les 2 inserts distincts qui se produisent dans la même transaction sur une seule ligne.

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;