2140 votes

Recherche de valeurs dupliquées dans une table SQL

Il est facile de trouver les doublons avec un seul champ :

SELECT name, COUNT(email) 
FROM users
GROUP BY email
HAVING COUNT(email) > 1

Donc si nous avons une table

ID   NAME   EMAIL
1    John   asd@asd.com
2    Sam    asd@asd.com
3    Tom    asd@asd.com
4    Bob    bob@asd.com
5    Tom    asd@asd.com

Cette requête nous donnera John, Sam, Tom, Tom parce qu'ils ont tous la même email .

Cependant, ce que je veux, c'est obtenir les doublons avec le même nom. email et name .

C'est-à-dire que je veux obtenir "Tom", "Tom".

La raison pour laquelle j'en ai besoin : J'ai fait une erreur, et j'ai permis l'insertion de duplicata name et email valeurs. Maintenant, je dois supprimer/modifier les doublons, donc je dois trouver les premiers.

35 votes

Je ne pense pas qu'il vous laisserait sélectionner le nom dans votre premier échantillon puisqu'il n'est pas dans une fonction d'agrégation. "Quel est le nombre d'adresses électroniques et de noms correspondants" est une logique délicate...

4 votes

J'ai découvert que cela ne fonctionne pas avec le serveur MSSQL à cause de la name dans le champ SELECT.

0 votes

Ce dont j'ai besoin, c'est l'identifiant des enregistrements dont l'email est dupliqué.

3333voto

gbn Points 197263
SELECT
    name, email, COUNT(*)
FROM
    users
GROUP BY
    name, email
HAVING 
    COUNT(*) > 1

Il suffit de regrouper sur les deux colonnes.

Remarque : la norme ANSI la plus ancienne consiste à inclure toutes les colonnes non agrégées dans le GROUP BY. "dépendance fonctionnelle" :

Dans la théorie des bases de données relationnelles, une dépendance fonctionnelle est une contrainte entre deux ensembles d'attributs dans une relation d'une base de données. En d'autres termes, la dépendance fonctionnelle est une contrainte qui décrit la relation entre les attributs d'une relation.

Le soutien n'est pas cohérent :

98 votes

@webXL WHERE fonctionne avec un seul enregistrement HAVING fonctionne avec un groupe

9 votes

@gbn Est-il possible d'inclure l'Id dans les résultats ? Il serait alors plus facile de supprimer ces doublons par la suite.

14 votes

@user797717 : vous devez avoir MIN(ID) et ensuite supprimer les valeurs d'ID qui ne sont pas dans le dernier if MIN(ID).

401voto

KM. Points 51800

Essayez ceci :

declare @YourTable table (id int, name varchar(10), email varchar(50))

INSERT @YourTable VALUES (1,'John','John-email')
INSERT @YourTable VALUES (2,'John','John-email')
INSERT @YourTable VALUES (3,'fred','John-email')
INSERT @YourTable VALUES (4,'fred','fred-email')
INSERT @YourTable VALUES (5,'sam','sam-email')
INSERT @YourTable VALUES (6,'sam','sam-email')

SELECT
    name,email, COUNT(*) AS CountOf
    FROM @YourTable
    GROUP BY name,email
    HAVING COUNT(*)>1

SORTIE :

name       email       CountOf
---------- ----------- -----------
John       John-email  2
sam        sam-email   2

(2 row(s) affected)

si vous voulez les ID des dups, utilisez ceci :

SELECT
    y.id,y.name,y.email
    FROM @YourTable y
        INNER JOIN (SELECT
                        name,email, COUNT(*) AS CountOf
                        FROM @YourTable
                        GROUP BY name,email
                        HAVING COUNT(*)>1
                    ) dt ON y.name=dt.name AND y.email=dt.email

SORTIE :

id          name       email
----------- ---------- ------------
1           John       John-email
2           John       John-email
5           sam        sam-email
6           sam        sam-email

(4 row(s) affected)

pour essayer de supprimer les doublons :

DELETE d
    FROM @YourTable d
        INNER JOIN (SELECT
                        y.id,y.name,y.email,ROW_NUMBER() OVER(PARTITION BY y.name,y.email ORDER BY y.name,y.email,y.id) AS RowRank
                        FROM @YourTable y
                            INNER JOIN (SELECT
                                            name,email, COUNT(*) AS CountOf
                                            FROM @YourTable
                                            GROUP BY name,email
                                            HAVING COUNT(*)>1
                                        ) dt ON y.name=dt.name AND y.email=dt.email
                   ) dt2 ON d.id=dt2.id
        WHERE dt2.RowRank!=1
SELECT * FROM @YourTable

SORTIE :

id          name       email
----------- ---------- --------------
1           John       John-email
3           fred       John-email
4           fred       fred-email
5           sam        sam-email

(4 row(s) affected)

0 votes

* Les noms de table sont sensibles à la cassearray(3) { [0]=> string(5) "42000" [1]=> int(1064) [2]=> string(226) "Vous avez une erreur dans votre syntaxe SQL ; vérifiez le manuel correspondant à votre version du serveur MySQL pour la bonne syntaxe à utiliser près de '(PARTITION BY y.employee_id, y.leave_type_id ) AS RowRank ' à la ligne 1" }

136voto

Chris Van Opstal Points 16961

Essayez ça :

SELECT name, email
FROM users
GROUP BY name, email
HAVING ( COUNT(*) > 1 )

53voto

gaurav singh Points 31

Contrairement à d'autres réponses, vous pouvez voir le ensemble du site les dossiers. Dans le PARTITION BY partie de numéro de rang choisissez les colonnes uniques/duplicites souhaitées.

SELECT  *
FROM    (
 SELECT a.*
 ,      Row_Number() OVER (PARTITION BY Name, Age ORDER BY Name) AS r
 FROM   Customers AS a
)       AS b
WHERE   r > 1;

3 votes

Une légère modification de SELECT * m'a permis de résoudre une recherche d'une heure. Je n'avais jamais utilisé la fonction OVER(PARTITION BY) auparavant. Je ne cesse d'être étonné par le nombre de façons de faire la même chose en SQL !

20voto

xDBA Points 11

Si vous travaillez avec Oracle, cette méthode est préférable :

create table my_users(id number, name varchar2(100), email varchar2(100));

insert into my_users values (1, 'John', 'asd@asd.com');
insert into my_users values (2, 'Sam', 'asd@asd.com');
insert into my_users values (3, 'Tom', 'asd@asd.com');
insert into my_users values (4, 'Bob', 'bob@asd.com');
insert into my_users values (5, 'Tom', 'asd@asd.com');

commit;

select *
  from my_users
 where rowid not in (select min(rowid) from my_users group by name, email);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X