I have two tables to handle attachments:
id
and other infoid_file
(the id
in the table files
is the foreign key) and other info of the attachments.Two tables to be able to share a file without duplicating it on the server (for your information).
When I delete an attachment, I want to delete the file only if there is no attachement left referring to its id
.
I have this request, to delete all the attachments linked to a particular item (the 26th item of the table 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
);
The problem is:
DELETE
with the ids
returned by the first delete, they are correctly deleted.Is there some mechanism that keeps a shallow copy of the table with the deleted items, thus making the deletion of items impossible?
As the documentation says,
The sub-statements in
WITH
are executed concurrently with each other and with the main query. Therefore, when using data-modifying statements inWITH
, the order in which the specified updates actually happen is unpredictable. All the statements are executed with the same snapshot (see Chapter 13), so they cannot “see” one another's effects on the target tables. This alleviates the effects of the unpredictability of the actual order of row updates, and means thatRETURNING
data is the only way to communicate changes between differentWITH
sub-statements and the main query.
My advice is to run two separate DELETE
statements. If you need them to share the same snapshot, run them in a REPEATABLE READ
transaction. If the reason for using a single statement was a constraint, you can use a deferred constraint instead. Use a temporary table for the rows deleted by the first statement.