Как я могу правильно обновить значение моей строки после того, как она была обновлена - PullRequest
1 голос
/ 25 февраля 2020

Я пытаюсь отслеживать, как меняются мои данные,

Я работаю с нестандартным решением, потому что я буду отслеживать эти изменения только при запуске сценария.

Что важнее всего для меня это иметь previous_value и value_after_update

INSERT INTO audit_details 
    (updated_table, updated_column, query, value_before_update, value_after_update)

SELECT 'some_table', 'some_column', query, enabled, (Here I've tried to put same query as it's contained on update because that value will be there after update),
FROM some_table WHERE product_id = _new_product_id;


UPDATE some_table
SET enabled = CASE WHEN (SELECT 1 FROM some_table WHERE enabled = true AND product_type = T1.product_type AND product_id = ANY(_previous_product_ids)) IS NOT NULL
    THEN true
    ELSE enabled END,
    THEN true
    ELSE accepted END
WHERE product_id = _new_product_id;

Как вы можете заметить, ребята, проблема в том, что я не знаю, как правильно вставить также values_after_update Я должен как-то повторить блок из обновления в мою вставку в выше (я пробовал это, даже если я не мог запустить его, это был большой и уродливый XD)?

Любая помощь была бы удивительной!

Спасибо

Приветствия

1 Ответ

1 голос
/ 25 февраля 2020

Это можно сделать с помощью одного оператора, объединяющего несколько 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 ....) и затем отключите его. Вы также можете создать для этого функцию, аналогичную этой

...