Bạn có thể tham gia vào cùng một bảng trên các trường sẽ được sao chép và sau đó chống tham gia trên trường id. Chọn trường id từ bí danh bảng đầu tiên (tn1) và sau đó sử dụng hàm Array_agg trên trường id của bí danh bảng thứ hai. Cuối cùng, để hàm Array_agg hoạt động chính xác, bạn sẽ nhóm các kết quả theo trường tn1.id. Điều này sẽ tạo ra một tập kết quả chứa id của bản ghi và một mảng của tất cả các id phù hợp với điều kiện nối.
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;
Rõ ràng, các id sẽ nằm trong mảng trùng lặp cho một id, cũng sẽ có các mục riêng trong tập kết quả. Bạn sẽ phải sử dụng tập kết quả này để quyết định id nào bạn muốn trở thành nguồn gốc của 'sự thật'. Một bản ghi không nên bị xóa. Có lẽ bạn có thể làm một cái gì đó như thế này:
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)
Chọn số ID thấp nhất có trùng lặp (giả sử ID đang tăng int PK). Đây sẽ là những ID mà bạn sẽ giữ xung quanh.