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’;