【问题标题】:DELETE recursive PostgreSQL删除递归 PostgreSQL
【发布时间】:2017-05-12 19:39:27
【问题描述】:

我有一个表 upload_temp,如下所示:

CREATE TABLE upload_temp (
    codigo serial PRIMARY KEY NOT NULL,
    codigo_upload_temp_pai INTEGER,
    nome TEXT NOT NULL,
    codigo_extensao INTEGER,
    data_inclusao TIMESTAMP NOT NULL DEFAULT NOW(),
    codigo_usuario_inclusao INTEGER NOT NULL,

    CONSTRAINT fk_upload_upload_pai FOREIGN KEY (codigo_upload_temp_pai) REFERENCES upload_temp (codigo) MATCH SIMPLE ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_extensao_upload FOREIGN KEY (codigo_extensao) REFERENCES extensao (codigo) MATCH SIMPLE ON UPDATE CASCADE ON DELETE NO ACTION,
    CONSTRAINT fk_usuario_upload FOREIGN KEY (codigo_usuario_inclusao) REFERENCES usuario (chave) MATCH SIMPLE ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT uq_upload UNIQUE('nome', COALESCE('codigo_extensao', -1), COALESCE('codigo_upload_temp_pai', -1), 'codigo_usuario_inclusao', DATE(data_inclusao))
);

此表存储我系统的所有临时上传,这些上传可以是文件夹文件。桌子上的自参考功能可以解决这个问题。但问题是:当某些文件注册到系统时,它就变成了正式的数字文件,upload_temp 被删除了。当它被删除时,只有当它变成一个空文件夹时,它的父文件夹才必须被删除。通过这种方式,我需要从这棵树中删除所有文件夹,只要它们因失去唯一的孩子而变空。下图包含更多细节:

Tree of folders and files

文件5.jpg属于文件夹5,该文件属于文件夹4,以此类推。如果我选择将文件5.jpg注册到系统,它将从upload_temp中删除,这将清空文件夹5。因此,文件夹 5 为空,也必须删除,在这种情况下,所有父文件夹都会发生同样的情况。

虽然我使用的是 PHP,但我需要一个针对性能的 PostgreSQL 解决方案。我试图了解WITH RECURSIVE 的工作原理,但我遇到了困难。我编写了以下代码,该代码应该从文件 5.jpg 开始递归地删除所有父级,忽略空功能:

WITH RECURSIVE all_uploads (codigo, parent, ext, main) AS (
   SELECT ut1.codigo, ut1.codigo_upload_temp_pai AS parent, ut1.codigo_extensao AS ext, ut1.codigo AS main
   FROM upload_temp ut1

   UNION ALL

   SELECT ut2.codigo, ut2.codigo_upload_temp_pai AS parent, ut2.codigo_extensao AS ext, au.main
  FROM upload_temp ut2
   JOIN all_uploads au ON au.parent = ut2.codigo
)
DELETE FROM upload_temp WHERE codigo IN (SELECT codigo FROM all_uploads WHERE codigo = 486);

下图显示SELECT * FROM upload_temp ORDER BY codigo的结果:

Select result

好吧,它不工作。它只是删除一个文件。我能做些什么来解决这个问题?谢谢!

【问题讨论】:

  • 这次清晰多了
  • 屏幕截图上有列tamanho,但没有定义
  • 是的,“mimetype”也是如此。该表最近更新了,但对我需要的内容没有影响
  • 好吧,如果您可以轻松更改结构,为什么不将列 root_id 与 codigo_upload_temp_pai 一起添加?..

标签: php sql postgresql recursion self-reference


【解决方案1】:
WITH RECURSIVE all_uploads (codigo, parent, ext, main) AS (
 SELECT ut1.codigo, ut1.codigo_upload_temp_pai AS parent,
  ut1.codigo_extensao AS ext, ut1.codigo AS main
 FROM upload_temp ut1
 WHERE ut1.codigo = 486

 UNION ALL

SELECT ut2.codigo, ut2.codigo_upload_temp_pai AS parent,
 ut2.codigo_extensao AS ext, au.main
FROM upload_temp ut2
JOIN all_uploads au ON au.parent = ut2.codigo
)
DELETE FROM upload_temp WHERE codigo IN (SELECT codigo FROM all_uploads);

您必须将起点放在初始选择中(在 with 内),或者您必须以某种方式创建一个表示“树”顶部的伪列,这对于整个树中的每一行都是相同的。将初始选择中的“顶部位置”放在 with 中是更简单的解决方案。

【讨论】:

  • 完美!谢谢老兄!
  • 谢谢。如果它适合您,请随时接受答案。
猜你喜欢
  • 1970-01-01
  • 2011-02-08
  • 2014-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
相关资源
最近更新 更多