DELETE递归PostgreSQL尊重特定条件

时间:2017-01-04 17:21:01

标签: postgresql recursion sql-delete recursive-query multiple-conditions

几天前,我问了一个关于从PostgreSQL中删除WITH RECURSIVE的问题。有:

DELETE recursive PostgreSQL

工作正常:最初的意图是,只要最后一个子项被删除,就会递归删除父文件夹。以下图片更好地描述了它:

Files tree view

通过删除文件 5.jpg ,在这种情况下,所有父文件夹也将被删除。

但现在我必须删除父文件夹,只有当它们变空时,即丢失其唯一的子文件夹。我尝试了以下方法:

 WITH RECURSIVE all_uploads (codigo, parent, ext, uploader) AS (
    SELECT ut1.codigo, ut1.codigo_upload_temp_pai AS parent, ut1.codigo_extensao AS ext, ut1.codigo_usuario_inclusao AS uploader
    FROM upload_temp ut1
    WHERE ut1.codigo = 576

    UNION ALL

    SELECT ut2.codigo, ut2.codigo_upload_temp_pai AS parent, ut2.codigo_extensao AS ext, ut2.codigo_upload_temp_pai AS uploader
    FROM upload_temp ut2
    JOIN all_uploads au ON au.parent = ut2.codigo
    WHERE (SELECT ut3.codigo FROM upload_temp ut3 WHERE ut3.codigo_upload_temp_pai = ut2.codigo LIMIT 1) IS NULL
    AND ext IS NULL
    AND uploader = 1535
 )
 DELETE FROM upload_temp WHERE codigo IN (SELECT codigo FROM all_uploads);

我认为检查文件夹是否为空的唯一方法是考虑自我关系来执行子选择。如果SELECT ut3.codigo FROM upload_temp ut3 WHERE ut3.codigo_upload_temp_pai = ut2.codigo LIMIT 1) IS NULL返回 true ,则该文件夹为空。通过使用自引用功能(文件夹和文件的相同DB表),我知道它是一个文件夹,通过检查codigo_extensao字段(只有文件有扩展名)。

嗯,它没有用,它只删除我的 5.jpg 。任何提示?提前谢谢!

1 个答案:

答案 0 :(得分:0)

你不能像你想要的那样递归地删除。这里的逻辑是创建一个删除所需内容的查询,并以递归方式运行它,直到还有其他内容要删除。

这是一个完全符合您需要的功能:

CREATE OR REPLACE FUNCTION p_remove_empty_folders(_codigo_usuario_ integer) RETURNS integer AS $$
DECLARE
    AFFECTEDROWS integer;
BEGIN

    WITH a AS (
    DELETE FROM upload_temp WHERE codigo IN (SELECT ut1.codigo FROM upload_temp ut1 WHERE ut1.codigo_usuario_inclusao = _codigo_usuario_ AND ut1.codigo_extensao IS NULL AND NOT EXISTS (SELECT * FROM upload_temp ut2 WHERE ut2.codigo_upload_temp_pai = ut1.codigo)) 
    RETURNING 1
    )
    SELECT count(*) INTO AFFECTEDROWS FROM a;    

    WHILE AFFECTEDROWS > 0 LOOP

        WITH a AS (
        DELETE FROM upload_temp WHERE codigo IN (SELECT ut1.codigo FROM upload_temp ut1 WHERE ut1.codigo_usuario_inclusao = _codigo_usuario_ AND ut1.codigo_extensao IS NULL AND NOT EXISTS (SELECT * FROM upload_temp ut2 WHERE ut2.codigo_upload_temp_pai = ut1.codigo)) 
        RETURNING 1
        )
        SELECT count(*) INTO AFFECTEDROWS FROM a;

    END LOOP;

    RETURN 0;
END;
$$ LANGUAGE plpgsql;

氰!