仅使用SQL返回更新前的列值

仅使用SQL返回更新前的列值,第1张

仅使用SQL返回更新前的列值

问题
手册说明:

可选RETURNING子句导致UPDATe基于实际更新的每一行计算并返回值。FROM可以计算使用表的列和/或中提到的其他表的列的任何表达式。使用表列的新(更新后)值。该RETURNING列表的语法与的输出列表的语法相同SELECt。

大胆强调我的。无法访问RETURNING子句中的旧行。您可以通过触发器来解决此限制,也可以使用@SELECT 之前的分隔UPDATE符来解决此限制,如@Flimzy和@wildplasser所注释,将其包装在事务中,或如@MattDiPasquale发布,将其包装在CTE中。

没有并发写入的解决方案
但是,如果您在子句中加入表的另一个实例,则您要实现的目标效果很好FROM:

UPDATe tbl xSET    tbl_id = 23     , name = 'New Guy'FROM   tbl y     -- using the FROM clauseWHERe  x.tbl_id = y.tbl_id  -- must be UNIQUE NOT NULLAND    x.tbl_id = 3RETURNING y.tbl_id AS old_id, y.name AS old_name        , x.tbl_id          , x.name;

返回值:

 old_id | old_name | tbl_id |  name--------+----------+--------+---------  3     | Old Guy  | 23     | New Guy

用于自联接的列必须为UNIQUE NOT NULL。在简单的示例中,WHERe条件在同一列上tbl_id,但这只是巧合。适用于任何条件。

我使用8.4到13的PostgreSQL版本进行了测试。

并发写入负载的解决方案
有多种方法可以避免在同一行上进行并发写入 *** 作时出现竞争情况。(请注意,对不相关的行进行并发写入 *** 作完全没有问题。)一种简单,缓慢且确定(但昂贵)的方法是以SERIALIZABLE隔离级别运行事务:

BEGIN ISOLATION LEVEL SERIALIZABLE;UPDATe ... ;COMMIT;

但这可能太过分了。并且您需要准备在序列化失败的情况下重复 *** 作。

简单和快速(和一样并发写入负载可靠)是在明确的锁定一个行进行更新:

UPDATE tbl xSET    tbl_id = 24     , name = 'New Gal'FROM  (SELECt tbl_id, name FROM tbl WHERe tbl_id = 4 FOR UPDATE) y WHERe  x.tbl_id = y.tbl_idRETURNING y.tbl_id AS old_id, y.name AS old_name        , x.tbl_id          , x.name;

请注意WHERe条件如何移动到子查询(再次可以是任何东西),并且仅自我联接(在UNIQUE NOT NULL列上)保留在外部查询中。这保证了仅SELECT处理由内部锁定的行。WHERe稍后,条件可能会解决为一组不同的行。



欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5675745.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存