PostgreSQL 在请求结束之前不会考虑WITH 中的DELETE

问题描述 投票:0回答:1

我有两个表来处理附件:

  • “文件”,其中包含
    id
    和其他信息
  • “附件”包含
    id_file
    (表
    id
    中的
    files
    是外键)和附件的其他信息。

两个表能够共享文件,而无需在服务器上复制文件(供您参考)。

当我删除附件时,只有当没有附件引用其

id
时,我才想删除该文件。

我有这个请求,删除链接到特定项目的所有附件(表的第 26 项

TABLE_NAME

WITH deleted_files AS (
  DELETE FROM public.attachments a
  WHERE a.id_in_table = 26
    AND a.table_name = 'TABLE_NAME'
  RETURNING id_file
)
DELETE FROM public.files f
WHERE f.id IN (SELECT id FROM deleted_files)
  AND NOT EXISTS (
    SELECT 1
    FROM public.attachments a
    WHERE a.id_file = f.id
);

问题是:

  • 附件被正确删除,但文件未被删除
  • 如果我再次运行相同的请求,则不会删除任何内容(这是正常的)
  • 如果我使用第一次删除返回的
    DELETE
    运行第二个
    ids
    ,它们将被正确删除。

是否有某种机制可以保留包含已删除项目的表的浅表副本,从而使项目无法删除?

sql postgresql sql-delete
1个回答
1
投票

正如文档所说,

WITH
中的子语句彼此并发执行并与主查询并发执行。因此,当在
WITH
中使用数据修改语句时,指定更新实际发生的顺序是不可预测的。所有语句都使用相同的快照执行(请参阅第 13 章),因此它们无法“看到”彼此对目标表的影响。这减轻了行更新实际顺序的不可预测性的影响,并且意味着
RETURNING
数据是在不同
WITH
子语句和主查询之间传达更改的唯一方式。

我的建议是运行两个单独的

DELETE
语句。如果您需要它们共享相同的快照,请在
REPEATABLE READ
事务中运行它们。如果使用单个语句的原因是约束,则可以改用延迟约束。对第一条语句删除的行使用临时表。

© www.soinside.com 2019 - 2024. All rights reserved.