更新后如何正确更新行的值
How can I properly update value of my row after it has been updated
我正在尝试跟踪我的数据是如何更改的,
我正在使用自定义解决方案,因为我只会在 运行 脚本时跟踪这些更改。
对我来说最重要的是拥有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)?
任何形式的帮助都会很棒!
谢谢
干杯
您可以通过一个链接多个 CTEs 的语句来实现这一点,该语句捕获 UPDATE 前后的旧值和新值。
然后您可以 "iterate" 通过将行转换为 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 语句的更改。
我会使用可以找到的许多现成的通用审计解决方案之一 here or here or here 并将通用触发器仅附加到那些 table 您需要它的地方。
或扩展触发器功能以检查例如一个 configuration setting and only store the changes if the property is set to e.g. true
. Then if you want to "debug" your statements turn on the audit logging (set session ....
) and turn it off afterwards. You can also create a function for that, similar
我正在尝试跟踪我的数据是如何更改的,
我正在使用自定义解决方案,因为我只会在 运行 脚本时跟踪这些更改。
对我来说最重要的是拥有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)?
任何形式的帮助都会很棒!
谢谢
干杯
您可以通过一个链接多个 CTEs 的语句来实现这一点,该语句捕获 UPDATE 前后的旧值和新值。
然后您可以 "iterate" 通过将行转换为 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 语句的更改。
我会使用可以找到的许多现成的通用审计解决方案之一 here or here or here 并将通用触发器仅附加到那些 table 您需要它的地方。
或扩展触发器功能以检查例如一个 configuration setting and only store the changes if the property is set to e.g. true
. Then if you want to "debug" your statements turn on the audit logging (set session ....
) and turn it off afterwards. You can also create a function for that, similar