Ricerca di valori duplicati in una tabella SQL


1936

È facile trovare duplicati con un campo:

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

Quindi se abbiamo un tavolo

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

Questa query ci darà John, Sam, Tom, Tom perché hanno tutti lo stesso email.

Tuttavia, quello che voglio è ottenere duplicati con lo stesso email e name .

Cioè, voglio ottenere "Tom", "Tom".

Il motivo per cui ho bisogno di questo: ho fatto un errore e ho permesso di inserire duplicati namee emailvalori. Ora ho bisogno di rimuovere / modificare i duplicati, quindi ho bisogno di trovare loro per primi.


28
Non credo che ti permetterebbe di selezionare il nome nel tuo primo campione poiché non è in una funzione aggregata. "Qual è il conteggio degli indirizzi e-mail corrispondenti e il loro nome" è una logica complicata ...
sxe

3
Trovato che questo non funziona con il server MSSQL a causa del namecampo in SELECT.
E. van Putten,

quello di cui ho bisogno è l'id dei record con email duplicate
Marcos Di Paolo,

Risposte:


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

Raggruppa semplicemente su entrambe le colonne.

Nota: lo standard ANSI più vecchio prevede di avere tutte le colonne non aggregate in GROUP BY ma ciò è cambiato con l'idea di "dipendenza funzionale" :

Nella teoria dei database relazionali, una dipendenza funzionale è un vincolo tra due insiemi di attributi in una relazione da un database. In altre parole, la dipendenza funzionale è un vincolo che descrive la relazione tra attributi in una relazione.

Il supporto non è coerente:


92
@webXL DOVE funziona con un singolo record HAVING funziona con il gruppo
bjan l'

8
@gbn È possibile includere l'ID nei risultati? Quindi sarebbe più facile eliminare quei duplicati in seguito.
user797717

13
@utente797717: dovresti avere MIN (ID) e quindi eliminare per i valori ID non nell'ultimo se valori MIN (ID)
gbn

1
Che dire dei casi in cui una delle colonne ha valori null?
Ankit Dhingra,

1
Grazie mille per questo, e sì, funziona in Oracle, anche se avevo bisogno di unicità della condizione, quindi piuttosto che>1 =1
Bill Naylor

370

prova questo:

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

PRODUZIONE:

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

(2 row(s) affected)

se vuoi gli ID dei dups usa questo:

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

PRODUZIONE:

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

(4 row(s) affected)

per eliminare i duplicati prova:

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

PRODUZIONE:

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

(4 row(s) affected)

127

Prova questo:

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

72

Se vuoi eliminare i duplicati, ecco un modo molto più semplice per farlo che dover trovare righe pari / dispari in una tripla sottoselezione:

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

E quindi per eliminare:

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
)

Molto più facile da leggere e comprendere IMHO

Nota: l'unico problema è che è necessario eseguire la richiesta fino a quando non vengono eliminate righe, poiché si elimina solo 1 di ogni duplicato ogni volta


2
Bello e facile da leggere; Vorrei trovare un modo per eliminare più righe duplicate in una volta sola.
Dickon Reed,

1
Questo non funziona per me come capiscoYou can't specify target table 'users' for update in FROM clause
Whitecat il

1
@Whitecat sembra un semplice problema di MySQL: stackoverflow.com/questions/4429319/...
AncAinu

1
Non funziona per me. Ottengo: "DBD :: CSV :: st execute fallito: uso del valore non inizializzato $ _ [1] nell'elemento hash in /Users/hornenj/perl5/perlbrew/perls/perl-5.26.0/lib/site_perl/5.26. 0 / SQL / Eval.pm line 43 "
Nigel Horne,

1
Penso che dove la clausola dovrebbe essere "u.name = u2.name AND u.email = u2.email AND (u.id> u2.id OR u2.id> u.id)" non è vero?
GiveEmTheBoot,

48

Prova quanto segue:

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

3
Una leggera modifica a SELEZIONA * mi ha aiutato a risolvere un'ora di ricerca. Non ho mai usato OVER (PARTITION BY prima. Non smetto mai di stupirmi di quanti modi per fare la stessa cosa in SQL!
Joe Ruder

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

28

Un po 'tardi alla festa, ma ho trovato una soluzione davvero interessante per trovare tutti gli ID duplicati:

SELECT GROUP_CONCAT( id )
FROM users
GROUP BY email
HAVING ( COUNT(email) > 1 )

2
Sembra essere uno zucchero sintattico aggirare. Bella scoperta.
Chef_Code

3
Tieni presente che GROUP_CONCATsi fermerà dopo una certa lunghezza predeterminata, quindi potresti non ottenere tutte le ids.
v010dya,

24

prova questo codice

WITH CTE AS

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

23

Questo seleziona / elimina tutti i record duplicati tranne un record da ciascun gruppo di duplicati. Quindi, l'eliminazione lascia tutti i record univoci + un record da ciascun gruppo di duplicati.

Seleziona duplicati:

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

Elimina duplicati:

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

Essere consapevoli di grandi quantità di record, può causare problemi di prestazioni.


2
Errore nella query di eliminazione - Non è possibile specificare la tabella di destinazione "città" per l'aggiornamento nella clausola FROM
Ali Azhar

2
Non ci sono né tabelle "città" né clausole di aggiornamento. Cosa intendi? Dov'è un errore nella query di eliminazione?
Martin Silovský,

2
Come funziona con i dati di OP?
giovedì

3
Cosa significa "OP"?
Martin Silovský,

19

Nel caso in cui lavori con Oracle, in questo modo sarebbe preferibile:

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);

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

2
Sullo Stack Overflow vengono visualizzate le risposte solo al codice, potresti spiegare perché questo risponde alla domanda?
Rich Benner,

2
@RichBenner: non ho trovato la risposta come, ogni riga nel risultato e che ci dice quali sono tutte righe duplicate e quali non sono in un colpo d'occhio e che non raggruppare, perché se vogliamo combinare questo query con qualsiasi altro gruppo di query non è una buona opzione.
Narendra,

2
Aggiungendo Id all'istruzione select e filtrando su duplicati, ti dà la possibilità di eliminare gli ID duplicati e continuare su ciascuno di essi.
Antoine Reinhold Bertrand,

12

Se desideri vedere se ci sono righe duplicate nella tua tabella, ho usato di seguito Query:

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

insert into my_table values (1, 'shekh', 'shekh@rms.com');
insert into my_table values (1, 'shekh', 'shekh@rms.com');
insert into my_table values (2, 'Aman', 'aman@rms.com');
insert into my_table values (3, 'Tom', 'tom@rms.com');
insert into my_table values (4, 'Raj', 'raj@rms.com');


Select COUNT(1) As Total_Rows from my_table 
Select Count(1) As Distinct_Rows from ( Select Distinct * from my_table) abc 

11

Questa è la cosa facile che mi è venuta in mente. Utilizza un'espressione di tabella comune (CTE) e una finestra di partizione (penso che queste funzionalità siano in SQL 2008 e versioni successive).

Questo esempio trova tutti gli studenti con nome e dob duplicati. I campi che si desidera controllare per la duplicazione vanno nella clausola OVER. È possibile includere qualsiasi altro campo desiderato nella proiezione.

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


10

Come possiamo contare i valori duplicati ?? o viene ripetuto 2 volte o più di 2. contali, non in gruppo.

semplice come

select COUNT(distinct col_01) from Table_01

2
Come funzionerebbe per la domanda posta? Ciò non fornisce righe che duplicano informazioni in più colonne (ad es. "E-mail" e "nome") in righe diverse.
Jeroen,

10

Usando CTE possiamo anche trovare un valore duplicato come questo

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

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
/

8

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

Penso che questo funzionerà correttamente per cercare valori ripetuti in una determinata colonna.


6
Questo non aggiunge nulla alla risposta principale , e tecnicamente non differisce nemmeno dal codice OP pubblicato nella domanda.
Jeroen,

7
SELECT * FROM users u where rowid = (select max(rowid) from users u1 where
u.email=u1.email);

6

Anche questo dovrebbe funzionare, magari provalo.

  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)

Particolarmente buono nel tuo caso Se cerchi duplicati con qualche tipo di prefisso o cambiamenti generali come ad esempio un nuovo dominio nella posta. quindi puoi usare sostituire () in queste colonne


5

Se si desidera trovare dati duplicati (secondo uno o più criteri) e selezionare le righe effettive.

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
SELECT name, email,COUNT(email) 
FROM users 
WHERE email IN (
    SELECT email 
    FROM users 
    GROUP BY email 
    HAVING COUNT(email) > 1)

Non puoi usarlo COUNTsenza GROUP BY, a meno che non si riferisca all'intera tabella.
RalfFriedl,

Senza gruppo Da parte tua hai usato COUNT ma qui ho fatto un errore di battitura a scrivere COUNT
Mohammad Neamul Islam

3

Per eliminare i record i cui nomi sono duplicati

;WITH CTE AS    
(

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

DELETE FROM CTE WHERE T > 1

3

Per controllare da record duplicati in una tabella.

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

o

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

Per eliminare il record duplicato in una tabella.

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

o

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

1

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


1

Possiamo usare avere qui che funzionano su funzioni aggregate come mostrato di seguito

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

Qui come due campi id_account e dati vengono utilizzati con Count (*). Quindi, fornirà tutti i record che hanno più di una volta gli stessi valori in entrambe le colonne.

Per qualche ragione, abbiamo erroneamente mancato di aggiungere eventuali vincoli nella tabella del server SQL e i record sono stati inseriti duplicati in tutte le colonne con l'applicazione front-end. Quindi possiamo utilizzare la query seguente per eliminare la query duplicata dalla tabella.

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

Qui abbiamo preso tutti i record distinti della tabella originale e cancellato i record della tabella originale. Ancora una volta abbiamo inserito tutti i valori distinti dalla nuova tabella alla tabella originale e quindi eliminato la nuova tabella.


1

Potresti provare questo

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

1

La cosa più importante qui è avere la funzione più veloce. Anche gli indici dei duplicati dovrebbero essere identificati. L'unione automatica è una buona opzione, ma per avere una funzione più veloce è meglio prima trovare le righe che hanno duplicati e poi unirsi alla tabella originale per trovare l'id delle righe duplicate. Infine ordina per qualsiasi colonna tranne id per avere righe duplicate l'una vicino all'altra.

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;

0

È possibile utilizzare la parola chiave SELECT DISTINCT per eliminare i duplicati. Puoi anche filtrare per nome e ottenere tutti con quel nome su un tavolo.


0

Il codice esatto differirebbe a seconda che si desideri trovare anche righe duplicate o solo ID diversi con lo stesso indirizzo e-mail e nome. Se id è una chiave primaria o ha un vincolo univoco, questa distinzione non esiste, ma la domanda non la specifica. Nel primo caso puoi usare il codice fornito in molte altre risposte:

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

In quest'ultimo caso useresti:

SELECT name, email, COUNT(DISTINCT id)
FROM users
GROUP BY name, email
HAVING COUNT(DISTINCT id) > 1
ORDER BY COUNT(DISTINCT id) DESC
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.