web-dev-qa-db-fra.com

Recherche de valeurs en double dans une table SQL

Il est facile de trouver duplicates avec un champ:

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

Donc si on a 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 email.

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

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

La raison pour laquelle j'ai besoin de ceci: j'ai commis une erreur et autorisé à insérer des valeurs dupliquées name et email. Maintenant, j'ai besoin de supprimer/changer les doublons, donc je dois les trouver en premier.

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

Il suffit de grouper sur les deux colonnes.

Remarque: l'ancienne norme ANSI prévoyait que toutes les colonnes non agrégées soient regroupées dans 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 d'une base de données. En d'autres termes, la dépendance fonctionnelle est une contrainte qui décrit la relation entre des attributs dans une relation.

Le support n'est pas cohérent:

2472
gbn

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

SORTIE:

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

(2 row(s) affected)

si vous voulez les identifiants 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 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

SORTIE: 

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

(4 row(s) affected)
306
KM.

Essaye ça:

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

Si vous souhaitez supprimer les doublons, voici une façon beaucoup plus simple de le faire que de devoir rechercher 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 donc pour 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 duplicata à chaque fois.

50
AncAinu

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
34
gaurav singh
 SELECT name, email 
    FROM users
    WHERE email in
    (SELECT email FROM users
    GROUP BY email 
    HAVING COUNT(*)>1)
25
PRADEEPTA VIRLLEY

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 )
18
Indivision Dev

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 
15
Tanmay Nehete

Si 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);
14
xDBA

Ceci 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 de plus grandes quantités d'enregistrements, cela peut causer des problèmes de performance.  

13
Martin Silovský
select id,name,COUNT(*) from India group by Id,Name having COUNT(*)>1
8
Debendra Dash

Comment pouvons-nous compter les valeurs dupliquées?.

aussi simple que 

select COUNT(distinct col_01) from Table_01
7
Muhammad Tahir

Ceci est la chose facile que je suis venu avec. 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 trouve tous les étudiants avec un nom en double et une dob. Les champs que vous souhaitez vérifier pour la duplication vont dans la clause OVER. Vous pouvez inclure tous les autres champs de votre choix 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
6
Darrel Lee
select name, email
, case 
when ROW_NUMBER () over (partition by name, email order by name) > 1 then 'Yes'
else 'No'
end "duplicated ?"
from users
6
Narendra

Si vous souhaitez voir s'il existe des lignes en double dans votre table, 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 
6
shekhar singh

Cela devrait également fonctionner, peut-être l'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 bien dans votre cas Si vous recherchez des doublons qui ont une sorte de préfixe ou un changement général, comme nouveau domaine en courrier. alors vous pouvez utiliser replace () dans ces colonnes

5
veritaS
 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
/
5
naveed

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
5
Debendra Dash

Si vous souhaitez rechercher des données en double (selon un ou plusieurs critères) et sélectionnez 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/

4
Lauri Lubi
SELECT * FROM users u where rowid = (select max(rowid) from users u1 where
u.email=u1.email);
4
Panky031

Pour vérifier les doublons Enregistrez 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);

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);
0
Arun Solomon

Nous pouvons utiliser avoir ici qui travaillent sur les fonctions d'agrégat 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 eu tort d’avoir omis d’ajouter des contraintes dans la table du serveur SQL et les enregistrements ont été insérés en double dans toutes les colonnes avec 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é ceux de la table d'origine. De nouveau, nous avons inséré toutes les valeurs distinctes d'une nouvelle table dans la table d'origine, puis supprimé une nouvelle table.

0
Suraj Kumar

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

0
Parkofadown

Vous voudrez peut-être essayer ceci

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

Pour supprimer les 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
0
Sheriff