Encontrar valores duplicados en una tabla SQL


1936

Es fácil encontrar duplicados con un campo:

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

Entonces si tenemos una mesa

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

Esta consulta nos dará a John, Sam, Tom, Tom porque todos tienen lo mismo email.

Sin embargo, lo que quiero es obtener duplicados con el mismo email y name .

Es decir, quiero obtener "Tom", "Tom".

La razón por la que necesito esto: cometí un error y permití insertar duplicados namey emailvalores. Ahora necesito eliminar / cambiar los duplicados, así que primero necesito encontrarlos .


28
No creo que le permita seleccionar el nombre en su primera muestra, ya que no está en una función agregada. "¿Cuál es el recuento de direcciones de correo electrónico coincidentes y su nombre" es una lógica
engañosa

3
Descubrí que esto no funciona con el servidor MSSQL debido al namecampo en SELECT.
E. van Putten

lo que necesito es la identificación de los registros con correo electrónico duplicado
Marcos Di Paolo

Respuestas:


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

Simplemente agrupe en ambas columnas.

Nota: el estándar ANSI anterior es tener todas las columnas no agregadas en GROUP BY, pero esto ha cambiado con la idea de "dependencia funcional" :

En la teoría de bases de datos relacionales, una dependencia funcional es una restricción entre dos conjuntos de atributos en una relación de una base de datos. En otras palabras, la dependencia funcional es una restricción que describe la relación entre atributos en una relación.

El soporte no es consistente:


92
@webXL DONDE funciona con un solo registro HABER funciona con un grupo
bjan

8
@gbn ¿Es posible incluir el ID en los resultados? Entonces sería más fácil eliminar esos duplicados después.
user797717

13
@ user797717: necesitaría tener MIN (ID) y luego eliminar los valores de ID que no
estén

1
¿Qué pasa con los casos en que cualquiera de las columnas tiene valores nulos?
Ankit Dhingra

1
Muchas gracias por esto, y sí, funciona en Oracle, aunque necesitaba la singularidad de la condición, así que en lugar de>1 =1
Bill Naylor

370

prueba esto:

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

SALIDA:

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

(2 row(s) affected)

si quieres las ID de los dups usa esto:

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

SALIDA:

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

(4 row(s) affected)

para eliminar los duplicados intente:

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

SALIDA:

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

(4 row(s) affected)

127

Prueba esto:

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

72

Si desea eliminar los duplicados, esta es una forma mucho más simple de hacerlo que tener que buscar filas pares / impares en una triple selección secundaria:

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

Y para eliminar:

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
)

Mucho más fácil de leer y entender en mi humilde opinión

Nota: El único problema es que debe ejecutar la solicitud hasta que no se eliminen filas, ya que elimina solo 1 de cada duplicado cada vez


2
Agradable y fácil de leer; Sin embargo, me gustaría encontrar una forma de eliminar varias filas duplicadas de una vez.
Dickon Reed

1
Esto no funciona para mí cuando llegoYou can't specify target table 'users' for update in FROM clause
Whitecat

1
@Whitecat parece un simple problema de MySQL: stackoverflow.com/questions/4429319/…
AncAinu

1
Me falla. Obtengo: "DBD :: CSV :: st execute falló: uso del valor no inicializado $ _ [1] en el elemento hash en /Users/hornenj/perl5/perlbrew/perls/perl-5.26.0/lib/site_perl/5.26. 0 / SQL / Eval.pm línea 43 "
Nigel Horne

1
Creo que la cláusula where debería ser "u.name = u2.name AND u.email = u2.email AND (u.id> u2.id OR u2.id> u.id)" ¿no es así?
GiveEmTheBoot

48

Intenta lo siguiente:

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
Un ligero cambio en SELECT * me ayudó a resolver una búsqueda de una hora. Nunca he usado OVER (PARTITION BY antes. ¡Nunca dejo de sorprenderme de cuántas maneras de hacer lo mismo en SQL!
Joe Ruder

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

28

Un poco tarde para la fiesta, pero encontré una solución realmente genial para encontrar todas las ID duplicadas:

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

2
Parece ser una solución sintáctica de azúcar. Buen hallazgo
Chef_Code

3
Tenga en cuenta que GROUP_CONCATse detendrá después de una longitud predeterminada, por lo que es posible que no obtenga todos los ids.
v010dya

24

prueba este código

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

Esto selecciona / elimina todos los registros duplicados, excepto un registro de cada grupo de duplicados. Por lo tanto, la eliminación deja todos los registros únicos + un registro de cada grupo de duplicados.

Seleccionar duplicados:

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

Eliminar duplicados:

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

Tenga en cuenta las grandes cantidades de registros, puede causar problemas de rendimiento.


2
Error en la consulta de eliminación - No se puede especificar la tabla de destino 'ciudades' para actualizar en la cláusula FROM
Ali Azhar

2
No hay tabla 'ciudades' ni cláusula de actualización. ¿Qué quieres decir? ¿Dónde hay un error en la consulta de eliminación?
Martin Silovský

2
¿Cómo funciona eso con los datos de OP?
thoroc

3
¿Qué significa el "OP"?
Martin Silovský

19

En caso de que trabaje con Oracle, esta forma sería preferible:

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
Las respuestas de código solo están mal vistas en Stack Overflow, ¿podría explicar por qué esto responde la pregunta?
Rich Benner

2
@RichBenner: No encontré la respuesta como, cada una de las filas en el resultado y que nos dice cuáles son filas duplicadas y cuáles no están a la vista y no agruparlas, porque si queremos combinar esto consultar con cualquier otro grupo de consulta por no es una buena opción.
Narendra

2
Al agregar Id a la instrucción select y filtrar duplicados, le da la posibilidad de eliminar los identificadores duplicados y continuar con cada uno.
Antoine Reinhold Bertrand

12

Si desea ver si hay filas duplicadas en su tabla, utilicé la siguiente consulta:

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

Esto es lo fácil que se me ocurrió. Utiliza una expresión de tabla común (CTE) y una ventana de partición (creo que estas características están en SQL 2008 y versiones posteriores).

Este ejemplo encuentra a todos los estudiantes con nombre y nombre duplicados. Los campos que desea verificar para duplicar van en la cláusula OVER. Puede incluir cualquier otro campo que desee en la proyección.

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

¿Cómo podemos contar los valores duplicados? o se repite 2 veces o más de 2. solo cuéntelos, no en grupo.

tan simple como

select COUNT(distinct col_01) from Table_01

2
¿Cómo funcionaría esto para la pregunta formulada? Esto no proporciona filas que duplican información en varias columnas (por ejemplo, "correo electrónico" y "nombre") en diferentes filas.
Jeroen

10

Al usar CTE también podemos encontrar valores duplicados como este

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;

Creo que esto funcionará correctamente para buscar valores repetidos en una columna en particular.


66
Esto no agrega nada a la respuesta principal , y técnicamente ni siquiera difiere del código OP publicado en la pregunta.
Jeroen

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

6

Esto también debería funcionar, tal vez intentarlo.

  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)

Especialmente bueno en su caso Si busca duplicados que tienen algún tipo de prefijo o cambio general como, por ejemplo, un nuevo dominio en el correo. entonces puede usar replace () en estas columnas


5

Si desea encontrar datos duplicados (por uno o varios criterios) y seleccione las filas reales.

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)

No puede usar COUNTsin GROUP BY, a menos que se refiera a toda la tabla.
RalfFriedl

Sin Group By usaste COUNT pero aquí he cometido un error al escribir COUNT
Mohammad Neamul Islam

3

Para eliminar registros cuyos nombres están duplicados

;WITH CTE AS    
(

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

DELETE FROM CTE WHERE T > 1

3

Para verificar desde un registro duplicado en una tabla.

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

Para eliminar el registro duplicado en una tabla.

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

Podemos usar tener aquí que funciona en funciones agregadas como se muestra a continuación

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

Aquí, como dos campos, id_account y data se usan con Count (*). Por lo tanto, dará todos los registros que tengan más de una vez los mismos valores en ambas columnas.

Por alguna razón, por error, no hemos agregado ninguna restricción en la tabla del servidor SQL y los registros se han insertado por duplicado en todas las columnas con la aplicación front-end. Entonces podemos usar la consulta a continuación para eliminar la consulta duplicada de la tabla.

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

Aquí hemos tomado todos los registros distintos de la tabla original y eliminado los registros de la tabla original. Nuevamente, insertamos todos los valores distintos de la nueva tabla en la tabla original y luego eliminamos la nueva tabla.


1

Es posible que desee probar esto

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

1

Lo más importante aquí es tener la función más rápida. También se deben identificar los índices de duplicados. La unión automática es una buena opción, pero para tener una función más rápida, es mejor encontrar primero las filas que tienen duplicados y luego unirse a la tabla original para encontrar la identificación de las filas duplicadas. Finalmente ordene por cualquier columna, excepto id, para tener filas duplicadas una cerca de la otra.

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

Puede usar la palabra clave SELECT DISTINCT para deshacerse de los duplicados. También puede filtrar por nombre y poner a todos con ese nombre en una tabla.


0

El código exacto diferirá dependiendo de si desea encontrar filas duplicadas o solo identificadores diferentes con el mismo correo electrónico y nombre. Si id es una clave principal o tiene una restricción única, esta distinción no existe, pero la pregunta no lo especifica. En el primer caso, puede usar el código proporcionado en varias otras respuestas:

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

En este último caso usarías:

SELECT name, email, COUNT(DISTINCT id)
FROM users
GROUP BY name, email
HAVING COUNT(DISTINCT id) > 1
ORDER BY COUNT(DISTINCT id) DESC
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.