Используйте триггер Postgres для записи JSON только измененных полей - PullRequest
0 голосов
/ 27 апреля 2019

Есть ли способ получить JSON только измененных полей?

Теперь я использую следующий триггер, но вся строка печатается в журнале изменений.

Примеры таблиц:

TABLE tbl_changelog (
  tbl    TEXT,
  op   TEXT,
  new     JSON,
  old     JSON
);

TABLE tbl_items (
  f1    TEXT,
  f2    TEXT
);

Триггер:

CREATE OR REPLACE FUNCTION changelog_procedure() RETURNS trigger AS $$
BEGIN
INSERT INTO tbl_changelog(tbl, op, new, old)
VALUES (TG_TABLE_NAME, TG_OP, row_to_json(NEW), row_to_json(OLD));
RETURN NULL;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER changelog_items
AFTER INSERT OR UPDATE OR DELETE ON tbl_items
FOR EACH ROW EXECUTE PROCEDURE changelog_procedure();

После вставки и загрузки f2 и f1 журнал изменений выглядит следующим образом:

tbl_changelog
------------------------------------------------------------------
 tbl      |   op    | new                  |     old
------------------------------------------------------------------
tbl_items | INSERT  | {f1: "aa", f2: "bb"} | 
------------------------------------------------------------------
tbl_items | UPDATE  | {f1: "aa", f2: "cc"} | {f1: "aa", f2: "bb"}
------------------------------------------------------------------
tbl_items | UPDATE  | {f1: "dd", f2: "cc"} | {f1: "aa", f2: "cc"}
------------------------------------------------------------------

Я хотел бы записать только те изменения, которыеэто:

tbl_changelog
------------------------------------------------------------------
 tbl      |   op    | new                  |     old
------------------------------------------------------------------
tbl_items | INSERT  | {f1: "aa", f2: "bb"} | 
------------------------------------------------------------------
tbl_items | UPDATE  | {f2: "cc"}           | {f2: "bb"}
------------------------------------------------------------------
tbl_items | UPDATE  | {f1: "dd"}           | {f1: "aa"}
------------------------------------------------------------------

1 Ответ

1 голос
/ 27 апреля 2019

Ваша функция триггера не может работать нормально, она выдает ошибку при вставке строки:

ОШИБКА: запись "old" еще не назначена

ДЕТАЛИ: структура кортежазапись, еще не назначенная, является неопределенной.

Вы должны рассматривать три случая INSERT, UPDATE и DELETE отдельно:

create or replace function changelog_procedure() 
returns trigger as $$
declare
    json_new jsonb;
    json_old jsonb;
begin
    if tg_op = 'INSERT' then
        json_new:= to_jsonb(new);
    elsif tg_op = 'DELETE' then
        json_old:= to_jsonb(old);
    else
        select jsonb_object_agg(new_key, new_value), jsonb_object_agg(old_key, old_value)
        into json_new, json_old
        from jsonb_each(to_jsonb(new)) as n(new_key, new_value)
        join jsonb_each(to_jsonb(old)) as o(old_key, old_value) 
        on new_key = old_key and new_value <> old_value;
    end if;
    insert into tbl_changelog(tbl, op, new, old)
    values (tg_table_name, tg_op, json_new, json_old);
    return null;
end;
$$ language plpgsql;
...