Select 用于更新查询 returns 违反基数

Select for update query returns cardinality violation

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

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

cart 是一个 table,它以 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"

我已经确认 </code> 实际上是一个整数并指向现有的行,并且由于 <code>id 是主键,所以我不明白这怎么可能 return不止一排。

SELECT FOR UPDATE 是有问题的查询吗?如果 id 是主键,那么该查询 return 怎么可能超过一行。

看起来你可以简化为:

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

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

jsonb_build_object() 更简单,与您的 jsonb_insert() 相同。或者更简单,但是:

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

我和您一样感到惊讶,子查询(您不需要)会以某种方式 return 多于一行。似乎不可能。您确定这是错误消息的来源吗?