postgresql - 选择更新查询返回基数违规

标签 postgresql sql-update locking database-concurrency postgres-9.6

我们在 Google 管理的云数据库中的 Postgres 9.6.10 中运行此查询:

WITH update AS
  (UPDATE cart SET loyalty = loyalty || jsonb_insert('{}', '{coupon}', loyalty#>'{scan_coupon}' || $1) WHERE id = 
  (SELECT id FROM cart WHERE id = $2 AND status = $3 and item_version = $4 FOR UPDATE) returning *)
SELECT * FROM updated

cart 是一个以 id 作为主键的表。 loyalty 是一个 jsonb 列,item_version 是一个在某些操作上递增的函数,但在更新 item_version 之前预计会发生几次更新。 status 是一个枚举类型。

在高并发更新下我们很少会遇到以下错误:

Cardinality_violation, file: "nodeSubplan.c", line: "1127", message: "more than one row returned by a subquery used as an expression", pg_code: "21000", routine: "ExecSetParamPlan", severity: "ERROR", unknown: "ERROR"

我已经确认 $2 实际上是一个整数并指向现有行,并且由于 id 是主键,我不知道它如何返回超过一排。

有问题的查询是SELECT FOR UPDATE吗?如果 id 是主键,该查询如何返回多行。

最佳答案

看起来你可以简化为:

UPDATE cart
SET    loyalty = loyalty || jsonb_build_object('coupon', loyalty->'scan_coupon') || $1
WHERE  id  =  $2
AND    status = $3
AND    item_version = $4
RETURNING *;

UPDATE 锁定行的方式与嵌套 SELECT ... FOR UPDATE 的方式相同。

jsonb_build_object()更简单,与您的 jsonb_insert() 执行相同的操作。或者也许更简单:

SET    loyalty = jsonb_insert(loyalty, '{coupon}', loyalty->'scan_coupon') || $1

我和你一样惊讶,子查询(你不需要)会以某种方式返回不止一行。看来不可能。您确定这是错误消息的来源吗?

关于postgresql - 选择更新查询返回基数违规,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56435529/

相关文章:

Oracle - 从子表中删除行锁定父表

从 csv 读取数字时出现 python 错误

sql - 如何在 UPDATE 语句中使用 regexp_matches()?

MySQL:更新触发器。如果不匹配任何行,获取 UPDATE 的 where 子句中使用的列的值?

c# - 损坏的锁?魔术僵局?

表上的 MySQL 永久锁定

database - 为什么刷新物化 View 会同时阻止插入/更新?

postgresql - 是否可以执行需要在 Postgres 中过滤的更新插入?

PostgreSQL 中的字符串操作

SQL 更新具有不同值的多行,其中它们与列表中的值匹配