Comment trouver des enregistrements en double dans PostgreSQL

j'ai une table de base de données PostgreSQL appelée "user_links" qui permet actuellement les champs dupliqués suivants:

year, user_id, sid, cid

la contrainte unique est actuellement le premier champ appelé "id", cependant je cherche maintenant à ajouter une contrainte pour s'assurer que le year , user_id , sid et cid sont tous uniques mais je ne peux pas appliquer la contrainte parce que des valeurs dupliquées existent déjà qui violent cette contrainte.

Est-il un moyen de trouver tous les doublons?

100
demandé sur the Tin Man 2015-01-26 21:55:46

3 réponses

l'idée de base sera d'utiliser une requête imbriquée avec l'agrégation des nombres:

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

, Vous pouvez ajuster la clause where dans la requête interne pour affiner la recherche.


il y a une autre bonne solution pour ce qui est mentionné dans les commentaires, (mais tout le monde ne les lit pas):

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

ou moins:

SELECT (yourTable.*)::text, count(*)
FROM yourTable
GROUP BY yourTable.*
HAVING count(*) > 1
170
répondu Marcin Zablocki 2017-04-14 17:08:06

De " Trouver les doublons avec PostgreSQL ", voici la solution intelligente:

select * from (
  SELECT id,
  ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id asc) AS Row
  FROM tbl
) dups
where 
dups.Row > 1
54
répondu alexkovelsky 2017-05-23 11:55:10

vous pouvez joindre à la même table sur les champs qui seraient dupliqués et ensuite anti-joindre sur le champ id. Sélectionnez le champ id dans la première table alias (tn1), puis utilisez la fonction array_agg dans le champ id de la deuxième table alias. Enfin, pour que la fonction array_agg fonctionne correctement, vous regrouperez les résultats par tn1.champ d'identification. Ceci va produire un ensemble de résultats qui contient l'id d'un enregistrement et un tableau de tous les id qui correspondent aux conditions de jointure.

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;

évidemment, les id qui seront dans le tableau duplicate_entries pour un id, auront aussi leurs propres entrées dans le jeu de résultats. Vous devrez utiliser ce jeu de résultats pour décider quelle id vous voulez devenir la source de 'truth. Le seul disque qui ne devrait pas être effacé. Peut-être pourriez-vous faire quelque chose comme ceci:

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)

sélectionne le nombre le plus bas D'ID qui ont des doublons (en supposant que L'ID augmente int PK). Les ID que vous serait de les garder autour.

3
répondu pwnyexpress 2015-01-26 21:02:59