Recherche de valeurs en double dans une table SQL

1936

Il est facile de trouver des 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   [email protected]
2    Sam    [email protected]
3    Tom    [email protected]
4    Bob    [email protected]
5    Tom    [email protected]

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

Cependant, ce que je veux, c'est obtenir des doublons avec les mêmes email et name .

Autrement dit, je veux obtenir "Tom", "Tom".

La raison pour laquelle j'en ai besoin: j'ai fait une erreur et j'ai autorisé l'insertion de doublons nameet de emailvaleurs. Maintenant, je dois supprimer / modifier les doublons, donc je dois d' abord les trouver .

Alex
la source
28
Je ne pense pas que cela vous permettrait de sélectionner un nom dans votre premier échantillon car il ne fait pas partie d'une fonction d'agrégation. "Quel est le nombre d'adresses e-mail correspondantes et de leur nom" est une logique délicate ...
sXe
3
Trouvé que cela ne fonctionne pas avec le serveur MSSQL en raison du namechamp dans SELECT.
E. van Putten
ce dont j'ai besoin, c'est l'identifiant des enregistrements avec des e
Marcos Di Paolo

Réponses:

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

Regroupez simplement les deux colonnes.

Remarque: l'ancienne norme ANSI consiste à avoir toutes les colonnes non agrégées dans le GROUP BY, mais cela a changé avec l'idée de "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 à partir 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 support n'est pas cohérent:

gbn
la source
92
@webXL WHERE fonctionne avec un seul disque HAVING travaille avec le groupe
bjan
8
@gbn Est-il possible d'inclure l'ID dans les résultats? Il serait ensuite plus facile de supprimer ces doublons par la suite.
user797717
13
@ user797717: vous devez avoir MIN (ID), puis supprimer pour les valeurs d'ID ne figurant pas dans les dernières valeurs MIN (ID)
gbn
1
Qu'en est-il des cas où l'une des colonnes a des valeurs nulles?
Ankit Dhingra
1
Merci beaucoup pour cela, et oui, cela fonctionne dans Oracle, même si j'avais besoin d'unicité de la condition, donc plutôt que>1 =1
Bill Naylor
370

essaye ça:

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

PRODUCTION:

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

(2 row(s) affected)

si vous voulez que les ID des dups utilisent 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

PRODUCTION:

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

(4 row(s) affected)

pour supprimer les doublons, essayez:

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

PRODUCTION:

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

(4 row(s) affected)
KM.
la source
127

Essaye ça:

SELECT name, email
FROM users
GROUP BY name, email
HAVING ( COUNT(*) > 1 )
Chris Van Opstal
la source
72

Si vous souhaitez supprimer les doublons, voici une façon beaucoup plus simple de le faire que de trouver des lignes paires / impaires dans une triple sous-sélection:

SELECT id, name, email 
FROM users u, users u2
WHERE u.name = u2.name AND u.email = u2.email AND u.id > u2.id

Et ainsi supprimer:

DELETE FROM users
WHERE id IN (
    SELECT id/*, name, email*/
    FROM users u, users u2
    WHERE u.name = u2.name AND u.email = u2.email AND u.id > u2.id
)

Beaucoup plus facile à lire et à comprendre à mon humble avis

Remarque: le seul problème est que vous devez exécuter la demande jusqu'à ce qu'aucune ligne ne soit supprimée, car vous ne supprimez qu'un seul de chaque doublon à chaque fois

AncAinu
la source
2
Agréable et facile à lire; J'aimerais trouver un moyen de supprimer plusieurs lignes en double en une seule fois.
Dickon Reed
1
Cela ne fonctionne pas pour moi car je reçoisYou can't specify target table 'users' for update in FROM clause
Whitecat
1
@Whitecat semble être un simple problème MySQL: stackoverflow.com/questions/4429319/…
AncAinu
1
Échoue pour moi. J'obtiens: "Échec de l'exécution de DBD :: CSV :: st: utilisation de la valeur non initialisée $ _ [1] dans l'élément de hachage à /Users/hornenj/perl5/perlbrew/perls/perl-5.26.0/lib/site_perl/5.26. 0 / SQL / Eval.pm ligne 43 "
Nigel Horne
1
Je pense que la clause where devrait être "u.name = u2.name AND u.email = u2.email AND (u.id> u2.id OR u2.id> u.id)" n'est-ce pas?
GiveEmTheBoot
48

Essayez ce qui suit:

SELECT * FROM
(
    SELECT Id, Name, Age, Comments, Row_Number() OVER(PARTITION BY Name, Age ORDER By Name)
        AS Rank 
        FROM Customers
) AS B WHERE Rank>1
gaurav singh
la source
3
Un léger changement de SELECT * m'a aidé à résoudre une recherche d'une heure. Je n'ai jamais utilisé le OVER (PARTITION BY avant. Je ne cesse d'être étonné de voir combien de façons de faire la même chose en SQL!
Joe Ruder
33
 SELECT name, email 
    FROM users
    WHERE email in
    (SELECT email FROM users
    GROUP BY email 
    HAVING COUNT(*)>1)
PRADEEPTA VIRLLEY
la source
28

Un peu tard pour la fête, mais j'ai trouvé une solution de contournement vraiment cool pour trouver tous les ID en double:

SELECT GROUP_CONCAT( id )
FROM users
GROUP BY email
HAVING ( COUNT(email) > 1 )
Indivision Dev
la source
2
Semble être un sucre syntaxique à contourner. Belle trouvaille.
Chef_Code
3
Gardez à l'esprit que GROUP_CONCATcela s'arrêtera après une durée prédéterminée, de sorte que vous pourriez ne pas obtenir tous les ids.
v010dya
24

essayez ce code

WITH CTE AS

( SELECT Id, Name, Age, Comments, RN = ROW_NUMBER()OVER(PARTITION BY Name,Age ORDER BY ccn)
FROM ccnmaster )
select * from CTE 
Tanmay Nehete
la source
23

Cela sélectionne / supprime tous les enregistrements en double, sauf un enregistrement de chaque groupe de doublons. Ainsi, la suppression laisse tous les enregistrements uniques + un enregistrement de chaque groupe de doublons.

Sélectionnez les doublons:

SELECT *
FROM table
WHERE
    id NOT IN (
        SELECT MIN(id)
        FROM table
        GROUP BY column1, column2
);

Supprimer les doublons:

DELETE FROM table
WHERE
    id NOT IN (
        SELECT MIN(id)
        FROM table
        GROUP BY column1, column2
);

Soyez conscient des quantités plus importantes d'enregistrements, cela peut entraîner des problèmes de performances.

Martin Silovský
la source
2
Erreur lors de la suppression de la requête - Vous ne pouvez pas spécifier la table cible "villes" pour la mise à jour dans la clause FROM
Ali Azhar
2
Il n'y a ni table «villes» ni clause de mise à jour. Que voulez-vous dire? Où est une erreur dans la requête de suppression?
Martin Silovský
2
Comment cela fonctionne-t-il avec les données OP?
thoroc
3
Que signifie le "OP"?
Martin Silovský
19

Dans le cas où vous travaillez avec Oracle, cette méthode serait préférable:

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

insert into my_users values (1, 'John', '[email protected]');
insert into my_users values (2, 'Sam', '[email protected]');
insert into my_users values (3, 'Tom', '[email protected]');
insert into my_users values (4, 'Bob', '[email protected]');
insert into my_users values (5, 'Tom', '[email protected]');

commit;

select *
  from my_users
 where rowid not in (select min(rowid) from my_users group by name, email);
xDBA
la source
15
select name, email
, case 
when ROW_NUMBER () over (partition by name, email order by name) > 1 then 'Yes'
else 'No'
end "duplicated ?"
from users
Narendra
la source
2
Les réponses uniquement codées sont désapprouvées sur Stack Overflow, pourriez-vous expliquer pourquoi cela répond à la question?
Rich Benner du
2
@RichBenner: Je n'ai pas trouvé la réponse telle que, chaque ligne dans le résultat et qui nous dit quelles sont toutes les lignes en double et celles qui ne sont pas en un coup d'œil et celles à ne pas regrouper, car si nous voulons combiner cela requête avec tout autre groupe de requêtes par n'est pas une bonne option.
Narendra
2
L'ajout d'ID à l'instruction select et le filtrage sur les doublons vous donnent la possibilité de supprimer les ID dupliqués et de les conserver.
Antoine Reinhold Bertrand
12

Si vous souhaitez voir s'il y a des lignes en double dans votre tableau, j'ai utilisé ci-dessous la requête:

create table my_table(id int, name varchar(100), email varchar(100));

insert into my_table values (1, 'shekh', '[email protected]');
insert into my_table values (1, 'shekh', '[email protected]');
insert into my_table values (2, 'Aman', '[email protected]');
insert into my_table values (3, 'Tom', '[email protected]');
insert into my_table values (4, 'Raj', '[email protected]');


Select COUNT(1) As Total_Rows from my_table 
Select Count(1) As Distinct_Rows from ( Select Distinct * from my_table) abc 
shekhar Kumar
la source
11

C'est la chose la plus simple que j'ai trouvée. Il utilise une expression de table commune (CTE) et une fenêtre de partition (je pense que ces fonctionnalités sont dans SQL 2008 et versions ultérieures).

Cet exemple recherche tous les élèves avec un nom et un ddb en double. Les champs dont vous souhaitez vérifier la duplication se trouvent dans la clause OVER. Vous pouvez inclure tout autre champ souhaité dans la projection.

with cte (StudentId, Fname, LName, DOB, RowCnt)
as (
SELECT StudentId, FirstName, LastName, DateOfBirth as DOB, SUM(1) OVER (Partition By FirstName, LastName, DateOfBirth) as RowCnt
FROM tblStudent
)
SELECT * from CTE where RowCnt > 1
ORDER BY DOB, LName
Darrel Lee
la source
11
select id,name,COUNT(*) from user group by Id,Name having COUNT(*)>1
Debendra Dash
la source
10

Comment pouvons-nous compter les valeurs dupliquées ?? soit il est répété 2 fois ou supérieur à 2. il suffit de les compter, pas en groupe.

aussi simple que

select COUNT(distinct col_01) from Table_01
Muhammad Tahir
la source
2
Comment cela fonctionnerait-il pour la question posée? Cela ne donne pas de lignes qui dupliquent des informations dans plusieurs colonnes (par exemple "e-mail" et "nom") dans différentes lignes.
Jeroen
10

En utilisant CTE, nous pouvons également trouver une valeur en double comme celle-ci

with MyCTE
as
(
select Name,EmailId,ROW_NUMBER() over(PARTITION BY EmailId order by id) as Duplicate from [Employees]

)
select * from MyCTE where Duplicate>1
Debendra Dash
la source
9
 select emp.ename, emp.empno, dept.loc 
          from emp
 inner join dept 
          on dept.deptno=emp.deptno
 inner join
    (select ename, count(*) from
    emp
    group by ename, deptno
    having count(*) > 1)
 t on emp.ename=t.ename order by emp.ename
/
naveed
la source
8

SELECT id, COUNT(id) FROM table1 GROUP BY id HAVING COUNT(id)>1;

Je pense que cela fonctionnera correctement pour rechercher des valeurs répétées dans une colonne particulière.

user4877838
la source
6
Cela n'ajoute pas grand-chose à la première réponse et, techniquement, ne diffère même pas vraiment du code OP affiché dans la question.
Jeroen
7
SELECT * FROM users u where rowid = (select max(rowid) from users u1 where
u.email=u1.email);
Panky031
la source
6

Cela devrait également fonctionner, peut-être essayer.

  Select * from Users a
            where EXISTS (Select * from Users b 
                where (     a.name = b.name 
                        OR  a.email = b.email)
                     and a.ID != b.id)

Particulièrement bon dans votre cas Si vous recherchez des doublons qui ont une sorte de préfixe ou un changement général comme par exemple un nouveau domaine dans la messagerie. alors vous pouvez utiliser replace () dans ces colonnes

veritaS
la source
5

Si vous souhaitez rechercher des données en double (selon un ou plusieurs critères) et sélectionner les lignes réelles.

with MYCTE as (
    SELECT DuplicateKey1
        ,DuplicateKey2 --optional
        ,count(*) X
    FROM MyTable
    group by DuplicateKey1, DuplicateKey2
    having count(*) > 1
) 
SELECT E.*
FROM MyTable E
JOIN MYCTE cte
ON E.DuplicateKey1=cte.DuplicateKey1
    AND E.DuplicateKey2=cte.DuplicateKey2
ORDER BY E.DuplicateKey1, E.DuplicateKey2, CreatedAt

http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/

Lauri Lubi
la source
4
SELECT name, email,COUNT(email) 
FROM users 
WHERE email IN (
    SELECT email 
    FROM users 
    GROUP BY email 
    HAVING COUNT(email) > 1)
Mohammad Neamul Islam
la source
Vous ne pouvez pas l'utiliser COUNTsans GROUP BY, sauf s'il fait référence à l'ensemble du tableau.
RalfFriedl
Sans Group By, vous avez utilisé COUNT mais ici, je fais une erreur de frappe pour écrire COUNT
Mohammad Neamul Islam
3

Pour supprimer des enregistrements dont les noms sont en double

;WITH CTE AS    
(

    SELECT ROW_NUMBER() OVER (PARTITION BY name ORDER BY name) AS T FROM     @YourTable    
)

DELETE FROM CTE WHERE T > 1
Shérif
la source
3

Pour vérifier à partir d'un enregistrement en double dans un tableau.

select * from users s 
where rowid < any 
(select rowid from users k where s.name = k.name and s.email = k.email);

ou

select * from users s 
where rowid not in 
(select max(rowid) from users k where s.name = k.name and s.email = k.email);

Pour supprimer l'enregistrement en double dans une table.

delete from users s 
where rowid < any 
(select rowid from users k where s.name = k.name and s.email = k.email);

ou

delete from users s 
where rowid not in 
(select max(rowid) from users k where s.name = k.name and s.email = k.email);
Arun Solomon
la source
1

SELECT column_name,COUNT(*) FROM TABLE_NAME GROUP BY column1, HAVING COUNT(*) > 1;

rahul kumar
la source
1

Nous pouvons utiliser avoir ici qui fonctionnent sur des fonctions d'agrégation comme indiqué ci-dessous

create table #TableB (id_account int, data int, [date] date)
insert into #TableB values (1 ,-50, '10/20/2018'),
(1, 20, '10/09/2018'),
(2 ,-900, '10/01/2018'),
(1 ,20, '09/25/2018'),
(1 ,-100, '08/01/2018')  

SELECT id_account , data, COUNT(*)
FROM #TableB
GROUP BY id_account , data
HAVING COUNT(id_account) > 1

drop table #TableB

Ici, deux champs id_account et data sont utilisés avec Count (*). Ainsi, il donnera à tous les enregistrements qui ont plus d'une fois les mêmes valeurs dans les deux colonnes.

Nous avons une raison erronée d'avoir manqué d'ajouter des contraintes dans la table SQL Server et les enregistrements ont été insérés en double dans toutes les colonnes avec l'application frontale. Ensuite, nous pouvons utiliser la requête ci-dessous pour supprimer la requête en double de la table.

SELECT DISTINCT * INTO #TemNewTable FROM #OriginalTable
TRUNCATE TABLE #OriginalTable
INSERT INTO #OriginalTable SELECT * FROM #TemNewTable
DROP TABLE #TemNewTable

Ici, nous avons pris tous les enregistrements distincts de la table d'origine et supprimé les enregistrements de la table d'origine. Encore une fois, nous avons inséré toutes les valeurs distinctes de la nouvelle table dans la table d'origine, puis supprimé la nouvelle table.

Suraj Kumar
la source
1

Vous voudrez peut-être essayer ceci

SELECT NAME, EMAIL, COUNT(*)
FROM USERS
GROUP BY 1,2
HAVING COUNT(*) > 1
adesh
la source
1

La chose la plus importante ici est d'avoir la fonction la plus rapide. Les indices des doublons doivent également être identifiés. L'auto-jointure est une bonne option mais pour avoir une fonction plus rapide, il est préférable de trouver d'abord les lignes qui ont des doublons, puis de se joindre à la table d'origine pour trouver l'id des lignes dupliquées. Enfin, triez par colonne, sauf id, pour avoir des lignes en double les unes à côté des autres.

SELECT u.*
FROM users AS u
JOIN (SELECT username, email
      FROM users
      GROUP BY username, email
      HAVING COUNT(*)>1) AS w
ON u.username=w.username AND u.email=w.email
ORDER BY u.email;
RyanAbnavi
la source
0

Vous pouvez utiliser le mot clé SELECT DISTINCT pour supprimer les doublons. Vous pouvez également filtrer par nom et placer tout le monde avec ce nom sur une table.

Parkofadown
la source
0

Le code exact diffère selon que vous souhaitez également rechercher des lignes en double ou uniquement des identifiants différents avec le même e-mail et le même nom. Si id est une clé primaire ou a une contrainte unique, cette distinction n'existe pas, mais la question ne le précise pas. Dans le premier cas, vous pouvez utiliser le code donné dans plusieurs autres réponses:

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

Dans ce dernier cas, vous utiliseriez:

SELECT name, email, COUNT(DISTINCT id)
FROM users
GROUP BY name, email
HAVING COUNT(DISTINCT id) > 1
ORDER BY COUNT(DISTINCT id) DESC
RET
la source