删除递归 PostgreSQL
DELETE recursive PostgreSQL
我有一个tableupload_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))
);
这个table存储了我系统的所有临时上传,这些上传可以是文件夹和文件。 table 上的自引用功能可以解决这个问题。但问题是:当某些文件注册到系统时,它成为一个正式的数字文件,upload_temp 被删除。删除时,其parent文件夹只有变成空文件夹才必须删除。通过这种方式,我需要从这棵树中删除所有文件夹,只要它们因丢失唯一的 child 而变空。下图包含更多细节:
Tree of folders and files
文件5.jpg属于文件夹5,属于文件夹4[=44] =],等等。如果我选择文件5.jpg注册到系统,它会从upload_temp中删除,这将清空 文件夹 5。因此 文件夹 5 是空的,因此也必须删除,在这种情况下,所有 parent 文件夹也会发生同样的情况。
虽然我使用的是 PHP,但我需要一个针对性能的 PostgreSQL 解决方案。我试图了解 WITH RECURSIVE
的工作原理,但我遇到了困难。我写了下面的代码应该递归地删除所有 parents,从文件 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
好吧,它不起作用。它只是删除一个文件。我能做些什么来解决这个问题?谢谢!
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);
您必须将起点放在初始 select 中(在 with 内)或者您必须以某种方式制作一个代表 "tree" 顶部的伪列,这对每个都相同在那整棵树中排行。将 "top where" 放在 with 中的初始 select 中是更简单的解决方案。
我有一个tableupload_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))
);
这个table存储了我系统的所有临时上传,这些上传可以是文件夹和文件。 table 上的自引用功能可以解决这个问题。但问题是:当某些文件注册到系统时,它成为一个正式的数字文件,upload_temp 被删除。删除时,其parent文件夹只有变成空文件夹才必须删除。通过这种方式,我需要从这棵树中删除所有文件夹,只要它们因丢失唯一的 child 而变空。下图包含更多细节:
Tree of folders and files
文件5.jpg属于文件夹5,属于文件夹4[=44] =],等等。如果我选择文件5.jpg注册到系统,它会从upload_temp中删除,这将清空 文件夹 5。因此 文件夹 5 是空的,因此也必须删除,在这种情况下,所有 parent 文件夹也会发生同样的情况。
虽然我使用的是 PHP,但我需要一个针对性能的 PostgreSQL 解决方案。我试图了解 WITH RECURSIVE
的工作原理,但我遇到了困难。我写了下面的代码应该递归地删除所有 parents,从文件 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
好吧,它不起作用。它只是删除一个文件。我能做些什么来解决这个问题?谢谢!
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);
您必须将起点放在初始 select 中(在 with 内)或者您必须以某种方式制作一个代表 "tree" 顶部的伪列,这对每个都相同在那整棵树中排行。将 "top where" 放在 with 中的初始 select 中是更简单的解决方案。