Как найти дубликаты записей в PostgreSQL

у меня есть таблица базы данных PostgreSQL под названием "user_links", которая в настоящее время позволяет следующие повторяющиеся поля:

year, user_id, sid, cid

уникальное ограничение в настоящее время является первым полем под названием "id", однако теперь я хочу добавить ограничение, чтобы убедиться, что year, user_id, sid и cid все уникальны, но я не могу применить ограничение, потому что повторяющиеся значения уже существуют, которые нарушают это ограничение.

есть ли способ найти все дубликаты?

3 ответов


основная идея будет использовать вложенный запрос с агрегацией count:

select * from yourTable ou
where (select count(*) from yourTable inr
where inr.sid = ou.sid) > 1

вы можете настроить предложение where во внутреннем запросе, чтобы сузить поиск.


есть еще одно хорошее решение для этого, упомянутое в комментариях (но не все их читают):

select Column1, Column2, count(*)
from yourTable
group by Column1, Column2
HAVING count(*) > 1

или короче:

SELECT (yourTable.*)::text, count(*)
FROM yourTable
GROUP BY yourTable.*
HAVING count(*) > 1

от "найти повторяющиеся строки с PostgreSQL " вот умное решение:

select * from (
  SELECT id,
  ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id asc) AS Row
  FROM tbl
) dups
where 
dups.Row > 1

вы можете присоединиться к той же таблице в полях, которые будут дублироваться, а затем анти-присоединиться к полю 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;

очевидно, 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)

выбирает наименьшее число ID, которые имеют дубликаты (предполагая, что ID увеличивает int PK). Это были бы документы, которые вы будет держаться поблизости.