Ви можете приєднатись до тієї ж таблиці на полях, які будуть дублюватись, а потім антиприєднатись до поля id. Виберіть поле id з псевдоніму першої таблиці (tn1), а потім скористайтеся функцією array_agg у полі id другого псевдоніма таблиці. Нарешті, щоб функція array_agg працювала належним чином, ви згрупуєте результати за полем tn1.id. Це створить набір результатів, який містить ідентифікатор запису та масив усіх ідентифікаторів, які відповідають умовам з'єднання.
select tn1.id,
array_agg(tn2.id) as duplicate_entries,
from table_name tn1 join table_name tn2 on
tn1.year = tn2.year
and tn1.sid = tn2.sid
and tn1.user_id = tn2.user_id
and tn1.cid = tn2.cid
and tn1.id <> tn2.id
group by tn1.id;
Очевидно, що ідентифікатори, які будуть знаходитись у масиві duplicate_entries для одного id, також матимуть власні записи у наборі результатів. Вам доведеться використовувати цей набір результатів, щоб вирішити, який ідентифікатор ви хочете стати джерелом "правди". Один запис, який не слід видаляти. Можливо, ви могли б зробити щось подібне:
with dupe_set as (
select tn1.id,
array_agg(tn2.id) as duplicate_entries,
from table_name tn1 join table_name tn2 on
tn1.year = tn2.year
and tn1.sid = tn2.sid
and tn1.user_id = tn2.user_id
and tn1.cid = tn2.cid
and tn1.id <> tn2.id
group by tn1.id
order by tn1.id asc)
select ds.id from dupe_set ds where not exists
(select de from unnest(ds.duplicate_entries) as de where de < ds.id)
Вибирає ідентифікатори з найменшим числом, у яких є дублікати (припускаючи, що ідентифікатор збільшується в PK). Це були б посвідчення особи, які ви б зберегли.