Это можно сделать с помощью одного оператора, объединяющего несколько CTE , который фиксирует старое и новое значение до и после ОБНОВЛЕНИЯ.
Затем вы можете «перебирать» столбцы, конвертируя строки в JSONB и извлекая измененные значения.
with old_data as (
-- collect the old values
select id, to_jsonb(t) as old_value
from some_table t
where product_id = 100
), new_data as (
-- this is where the actual UPDATE is done
-- change the SET part as you need it
update some_table
set enabled = false,
some_value = 4
where product_id = 100
-- this returns the modified values from the CTE
returning id, to_jsonb(some_table) as new_value
), changed_column_values as (
-- this converts the JSON values into one row per column
-- and selects those column values that have changed
-- it is assumed that the column some_table.id is the primary key
select nd.id, x.*
from new_data nd
join old_data od using (id)
join lateral (
select nd.id, n.col as column_name, o.value as old_column_value, n.value as new_column_value
from jsonb_each_text(nd.new_value) as n(col, value)
join jsonb_each_text(od.old_value) as o(col, value) on o.col = n.col and n.value is distinct from o.value
) x on x.id = nd.id
)
-- now insert the result of the previous comparison into the audit table
insert into audit_details (updated_table, updated_column, query, value_before_update, value_after_update)
select 'some_table', column_name, old_column_value, new_column_value
from changed_column_values
Онлайн-пример
Хотя приведенный выше код работает, он довольно уродлив и подвержен ошибкам, только чтобы отловить изменения для одного оператора UPDATE.
Я бы использовал одно из множества готовых универсальных c решений для аудита, которые можно найти здесь или здесь или здесь и прикрепляйте триггер generi c только к тем таблицам, где он вам нужен.
Или расширить функцию триггера, чтобы проверить, например, параметр конфигурации и сохранить изменения, только если для свойства установлено, например, true
. Затем, если вы хотите «отладить» ваши операторы, включите ведение журнала аудита (set session ....
) и затем отключите его. Вы также можете создать для этого функцию, аналогичную этой