Postgres SQL для соединения таблиц аудита родитель-потомок - PullRequest
1 голос
/ 22 сентября 2010

Мы используем "1 таблица аудита для каждой отслеживаемой таблицы" ; Однако в нашем случае emp(PARENT) таблица имеет дочернюю таблицу emp_address, которую также необходимо отслеживать, поэтому у нас есть emp_audit и emp_address_audit tables.

SQL аудита postgres: как объединить таблицы PARENT и CHILD для создания отчетов.

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

Мы используем hibernate (java) для постоянных обновлений и обновлений hibernate только для тех таблиц, столбцы которых были изменены в операции обновления. Учитывая это, у меня может быть несколько (скажем, 5) записей в таблице emp_addr_audit для 1 таблицы emp_audit.

В отчете требуется 1 строка для каждой транзакции (модификации). Отчет будет иметь следующие столбцы

empnum, empname, line1, line2, операция (вставка / удаление / обновление), loginid, время обновления

Давайте рассмотрим 2 сценария, чтобы понять, что нужно:

  1. В исходной транзакции создаются только атрибуты emp. Затем в отдельной транзакции создается соответствующая строка в emp_addr. Итак, теперь у нас есть 1 строка в таблице emp_audit и 1 строка в таблице emp_addr_audit. Отчет будет иметь 2 строки (по одной на каждую транзакцию).
  2. Оба атрибута emp и emp_addr создаются в одной транзакции. Это обеспечит наличие 1 строки в emp_audit и 1 строки в emp_addr_audit. Теперь отчет будет иметь ТОЛЬКО 1 строку (поскольку обе строки таблицы были созданы в одной транзакции).

Какой SQL удовлетворит оба вышеуказанных сценария?

UPDATE
Сценарий:
Транзакция № 1: Я вставляю строку в emp и emp_addr. Это приводит к строке, каждый в emp_audit и emp_addr_audit. (INSERT)
Транзакция № 2: Я обновляю вышеуказанный атрибут emp '. Это приводит к появлению строки ОБНОВЛЕНИЕ в emp_audit.
Транзакция № 3: Я обновляю вышеуказанный атрибут emp_addr. Это приводит к появлению строки ОБНОВЛЕНИЕ в emp_addr_audit.

Я попробовал следующий SQL # 1, и он вернул 3 строки, как и ожидалось;

SQL # 1

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

Однако, когда я добавил предложение where в SQL, он возвращает только 2 строки. Отсутствующая строка была результатом транзакции № 3, где только строка таблицы emp_addr была ОБНОВЛЕНА, а строка таблицы emp была нетронутой.
SQL # 2

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

Какой SQL ЕЩЕ будет в состоянии получить мне 3 строки для 3 транзакций, чтобы я все еще мог отфильтровать на основе empnum?

Спасибо,

1 Ответ

0 голосов
/ 22 сентября 2010

Сначала добавьте дополнительный столбец txid bigint в таблицы аудита, затем измените хранимый процесс, который выполняет аудит, для вызова txid_current(), чтобы сохранить текущий идентификатор транзакции с записью аудита.

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;

Затем, когда вам нужно сообщить, что записи аудита выполняют внешнее соединение между двумя таблицами, используя emp_id и txid, чтобы вы могли представить две отдельные вставки, которые происходят в одной транзакции, в одной строке.

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...