web-dev-qa-db-fra.com

Comment trouver des enregistrements en double dans PostgreSQL

J'ai une table de base de données PostgreSQL appelée "user_links" qui autorise actuellement les champs en double suivants:

year, user_id, sid, cid

La contrainte unique est actuellement le premier champ appelé "id", mais je cherche maintenant à ajouter une contrainte pour m'assurer que les variables year, user_id, sid et cid sont Tous sont uniques mais je ne peux pas appliquer la contrainte car des valeurs en double existent déjà et violent cette contrainte.

Est-il possible de trouver tous les doublons?

140
John

L'idée de base consistera à utiliser une requête imbriquée avec agrégation de comptes:

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 cela 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 plus court:

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

De " Trouver les lignes en double avec PostgreSQL ", voici une 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
73
alexkovelsky

Vous pouvez rejoindre la même table sur les champs à dupliquer, puis effectuer une anti-jointure sur le champ id. Sélectionnez le champ id dans le premier alias de table (tn1), puis utilisez la fonction array_agg sur le champ id du deuxième alias de table. Enfin, pour que la fonction array_agg fonctionne correctement, vous allez regrouper les résultats en fonction du champ tn1.id. Cela produira un ensemble de résultats contenant l'identifiant d'un enregistrement et un tableau de tous les identifiants répondant 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;

De toute évidence, les identifiants qui figureront dans le tableau duplicate_entries pour un identifiant auront également leurs propres entrées dans le jeu de résultats. Vous devrez utiliser cet ensemble de résultats pour décider quel identifiant vous voulez devenir la source de la "vérité". L'enregistrement qui ne devrait pas être supprimé. Peut-être que vous pourriez faire quelque chose comme ça:

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 les ID de numéros les plus bas qui ont des doublons (en supposant que l'ID augmente en PK). Ce sont les identifiants que vous garderiez.

4
pwnyexpress