Postgresql 更新行后,如何正确更新行的值

Postgresql 更新行后,如何正确更新行的值,postgresql,sql-insert,audit-logging,Postgresql,Sql Insert,Audit Logging,我试图追踪我的数据是如何改变的 我正在使用自定义解决方案,因为我将仅在运行脚本时跟踪这些更改 对我来说,最重要的是要有以前的值和更新后的值 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

我试图追踪我的数据是如何改变的

我正在使用自定义解决方案,因为我将仅在运行脚本时跟踪这些更改

对我来说,最重要的是要有
以前的值
更新后的值

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;
正如大家所注意到的,问题是,我不知道如何在更新后正确插入值,我应该以某种方式重复 阻止从更新到我上面的插入(我已经尝试过了,即使我不能运行它,它是大而丑陋的XD)

任何形式的帮助都会很棒

谢谢


Cheers

您可以通过一条语句链接多条语句来实现这一点,该语句捕获更新前后的旧值和新值

然后,您可以通过将行转换为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语句的更改就非常难看并且容易出错

我将使用许多现成的通用审计解决方案中的一个,这些解决方案可以找到,或者只将通用触发器附加到您需要的表中


或者扩展触发器功能,以检查是否存在更改,并且仅在属性设置为例如
true
时存储更改。然后,如果要“调试”语句,请打开审核日志(
set session…
),然后将其关闭。您还可以为此创建一个函数,类似的

您可以使用
SCOPE\u IDENTITY()
获取最后插入行的ID,而不是执行
SELECT
btw@JamesS:Postgres中没有
scope\u identity()
。你的意思是
lastval()
?@a_horse__ _no_name_你能给我举一个lastval()的例子吗?或者它是如何命名的,我一般在sql上要用5天。谢谢你的帮助@一匹没有名字的马我看到了sql标记并认为它是that@JamesS:在“SQL”中也没有
scope\u identity()
,我对数据库和所有东西都是新手,这很有帮助!我可以解释一下为什么要将行转换为JSONB?我现在就要努力学习!我可以说非常感谢!:)还有一个问题,先生,我测试过了,它真的很有效!谢谢若update语句的任何列发生更改,这将在audit_details表中插入新行,我怎么能说track only enabled列,而对于任何其他列,都不在audit表中插入新行呢?再次感谢你!也许我可以添加where on changed_column_值,例如where column_name‘column_to_avoid’;