Как найти дубликаты записей в 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). Это были бы документы, которые вы будет держаться поблизости.