问题
手册说明:
可选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稍后,条件可能会解决为一组不同的行。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)