PostgreSQL没有从WITH中删除行...AS UPDATE子句

cyej8jka  于 2023-05-06  发布在  PostgreSQL
关注(0)|答案(1)|浏览(292)

我想编写一个执行UPDATE的查询,如果结果行与约束匹配,则执行DELETE。
为了测试,我有下表:

# CREATE TABLE counts (id BIGSERIAL PRIMARY KEY, count BIGINT NOT NULL);
# INSERT INTO counts (count) VALUES (5), (1);
# SELECT * FROM counts;
 id | count 
----+-------
  1 |     5
  2 |     1
(2 rows)

现在,我编写了以下查询,从counts表中减去一个count,如果count变为0,则删除该行:

WITH updated_counts AS (
  UPDATE counts
  SET count=count - 1
  WHERE id=2
  RETURNING *
)
DELETE FROM counts
USING updated_counts
WHERE counts.id=updated_counts.id
  AND updated_counts.count=0;

在事务中运行此命令会更改counts表,但不会删除行(返回的标记为DELETE 0)。

# SELECT * FROM counts;
 id | count 
----+-------
  1 |     5
  2 |     0
(2 rows)

回滚这个事务并使用显示WITH子句结果的查询重试,我确实看到要删除的行具有正确的计数:

# WITH updated_counts AS (UPDATE counts 
                             SET count=count - 1
                           WHERE id=2
                       RETURNING *
                         )
SELECT *
  FROM updated_counts;

 id | count 
----+-------
  2 |     0
(1 row)

以下查询也没有预期的结果:

# WITH updated_counts AS (UPDATE counts
                             SET count=count - 1
                           WHERE id=2
                       RETURNING *)
DELETE
  FROM counts
 WHERE id IN (SELECT id
                FROM updated_counts
               WHERE count=0
             );
DELETE 0
# SELECT * FROM counts;
 id | count 
----+-------
  1 |     5
  2 |     0
(2 rows)

有人能解释一下为什么即使updated_counts包含正确的行,DELETE也没有删除它吗?理想情况下,如何修复查询以使其能够执行?
这是在Postgres服务器版本15.1,客户端版本14.7。

m1m5dgzv

m1m5dgzv1#

您不能在一条语句中**更新同一行两次。您可以分成两个语句或颠倒操作顺序。当你尝试更新一个不存在的行时,Postgres不会抛出错误。由于从列值中减去1,然后在结果为0时删除,这与删除初始值为1的列值是一样的,因此可以将updatedelete颠倒过来,先执行删除。所以:

with delete_1_counts as (
  delete from counts 
    where count = 1
      and id=2 
  returning id
)
update counts
   set count = count - 1
  from delete_1_counts  
where counts.id=delete_1_counts.id;

相关问题