-- Inspect duplicates first WITH duplicate_participants AS ( SELECT shipcall_id, participant_type, COUNT(*) AS cnt FROM times GROUP BY shipcall_id, participant_type HAVING COUNT(*) > 1 ) SELECT t.* FROM times AS t JOIN duplicate_participants AS d ON d.shipcall_id = t.shipcall_id AND (d.participant_type <=> t.participant_type) ORDER BY t.shipcall_id, t.participant_type, t.id; -- Delete all but the highest-id entry per (shipcall_id, participant_type) WITH ordered_times AS ( SELECT id, ROW_NUMBER() OVER ( PARTITION BY shipcall_id, participant_type ORDER BY id DESC ) AS rn FROM times ) DELETE FROM times WHERE id IN ( SELECT id FROM ordered_times WHERE rn > 1 ); -- Optional: re-check that no duplicates remain WITH duplicate_participants AS ( SELECT shipcall_id, participant_type, COUNT(*) AS cnt FROM times GROUP BY shipcall_id, participant_type HAVING COUNT(*) > 1 ) SELECT COUNT(*) AS remaining_duplicates FROM duplicate_participants;