Encontrar valores duplicados en MySQL


769

Tengo una tabla con una columna varchar, y me gustaría encontrar todos los registros que tienen valores duplicados en esta columna. ¿Cuál es la mejor consulta que puedo usar para encontrar los duplicados?


1
Como mencionó encontrar todos los registros, supongo que necesita conocer las CLAVES, así como los VALORES duplicados en esa columna varchar.
TechTravelThink

Puedo encontrar las claves lo suficientemente fácil después de obtener los valores, realmente solo quiero una lista de todos los valores duplicados.
Jon Tackabury

Respuestas:


1522

Haz un SELECTcon una GROUP BYcláusula. Digamos que nombre es la columna en la que desea encontrar duplicados:

SELECT name, COUNT(*) c FROM table GROUP BY name HAVING c > 1;

Esto devolverá un resultado con el valor del nombre en la primera columna y un recuento de cuántas veces aparece ese valor en la segunda.


27
Pero, ¿cómo es esto útil si no puede obtener los ID de las filas con valores duplicados? Sí, puede hacer una nueva consulta que coincida para cada valor duplicado, pero ¿es posible simplemente enumerar los duplicados?
NobleUplift

23
@NobleUplift Puede hacer un GROUP_CONCAT(id)y mostrará una lista de las ID. Vea mi respuesta para un ejemplo.
Matt Rardon

55
¿Qué significaría si dijera ERROR: column "c" does not exist LINE 1?
Usuario

15
Estoy confundido por qué esta es la respuesta aceptada y por qué tiene tantos votos a favor. El OP preguntó: "Me gustaría encontrar todos los registros que tienen valores duplicados en esta columna". Esta respuesta devuelve una tabla de recuentos. -1
Monica Heddneck

44
Para aquellos que no entienden cómo funciona HAVING, es simplemente un filtro en el conjunto de resultados, por lo que sucede después de la consulta principal.
John Hunt

236
SELECT varchar_col
FROM table
GROUP BY varchar_col
HAVING COUNT(*) > 1;

10
Superior a la respuesta de @ levik ya que no agrega una columna adicional. Lo hace útil para usar con IN()/ NOT IN().
wmassingham

172
SELECT  *
FROM    mytable mto
WHERE   EXISTS
        (
        SELECT  1
        FROM    mytable mti
        WHERE   mti.varchar_column = mto.varchar_column
        LIMIT 1, 1
        )

Esta consulta devuelve registros completos, no solo distintos varchar_column.

Esta consulta no usa COUNT(*). Si hay muchos duplicados, COUNT(*)es costoso y no necesita el todo COUNT(*), solo necesita saber si hay dos filas con el mismo valor.

Tener un índice en varchar_columnvoluntad, por supuesto, acelerará enormemente esta consulta.


3
Muy bien. Agregué ORDER BY varchar_column DESCal final de la consulta.
trante

8
Esta debe ser la respuesta aceptada, como GROUP BYy HAVINGdevoluciones solamente una de las posibles duplicados. Además, el rendimiento con un campo indexado en lugar de COUNT(*), y la posibilidad ORDER BYde agrupar registros duplicados.
Rémi Breton

1
Como se indicó en los comentarios anteriores, esta consulta le permite enumerar todas las filas duplicadas. Muy útil.
TryHarder

44
Mirando esto, no entiendo cómo funcionaría en absoluto. ¿La condición interna no siempre será verdadera ya que cualquier fila de la tabla externa también estará disponible en la tabla interna y, por lo tanto, cada fila siempre coincidirá por lo menos? Intenté la consulta y obtuve el resultado que sospechaba: cada fila regresaba. Pero con tantos votos positivos, dudo de mí mismo. ¿No le falta a la consulta interna algo como "AND mto.id <> mti.id"? A mí me funciona cuando agrego eso.
Clox

2
@Quassnoi Muy bien. Intenté ponerlo en sqlfiddle, pero me di por vencido ya que cada consulta que intento ejecutar, aparte de crear el esquema, se agota. Me di cuenta de que simplemente eliminar "EXISTS" también hace que la consulta funcione correctamente para mí.
Clox

144

A partir de la respuesta de levik para obtener los ID de las filas duplicadas, puede hacer GROUP_CONCATsi su servidor lo admite (esto devolverá una lista de identificadores separados por comas).

SELECT GROUP_CONCAT(id), name, COUNT(*) c FROM documents GROUP BY name HAVING c > 1;

12
¡Todo este tiempo sin saber acerca de GROUP_CONCAT ()! Muy muy útil.
aesede

Realmente apreciado Matt. ¡Esto es realmente útil! Para aquellos que intentan actualizar en phpmyadmin si dejan la identificación junto con la función de esta manera: SELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...]permite la edición en línea y debe actualizar todas las filas involucradas (o al menos la primera coincidente), pero desafortunadamente la edición genera un error de Javascript. ..
Armfoot

¿Cómo calcularía entonces cuántos identificadores están sujetos a duplicación?
CMCDragonkai

2
¿Cómo no obtengo todos los ID agrupados, sino que los enumero del primero al último? con todos sus valores respectivos en las columnas al lado de ellos? Entonces, en lugar de agruparlo, solo muestra ID 1 y su valor, ID 2 y su valor. INCLUSO si los valores para la ID son los mismos.
MailBlade

1
Respuesta extremadamente útil, esto debería ser superior para que más personas lo vean. Recuerdo cuánto dolor pasé creando tales listas, y estaba disponible todo el tiempo como comando ...
John

13

Suponiendo que su tabla se llama TableABC y la columna que desea es Col y la clave principal de T1 es Clave.

SELECT a.Key, b.Key, a.Col 
FROM TableABC a, TableABC b
WHERE a.Col = b.Col 
AND a.Key <> b.Key

La ventaja de este enfoque sobre la respuesta anterior es que proporciona la clave.


44
+1 Porque es útil. Aunque, irónicamente, el resultado en sí contiene duplicados (enumera a y b, luego b y a.)
Fabien Snauwaert

2
@FabienSnauwaert Puede deshacerse de algunos de los duplicados al comparar menos que (o más que)
Michael

@TechTravelThink su respuesta es muy clara, gracias por eso, pero en una tabla grande toma algo de tiempo (alrededor de 2 millones en más de 20'000 tablas de entradas) y después de mostrar 25 primeros resultados, si hago clic para mostrar la siguiente, phpmyadmin muestra error "# 1052 - La columna 'id' en la cláusula de pedido es ambigua "
bcag2

12
SELECT * 
FROM `dps` 
WHERE pid IN (SELECT pid FROM `dps` GROUP BY pid HAVING COUNT(pid)>1)

1
No, porque este es posiblemente el más lento de todos. Las subselecciones son notoriamente lentas, ya que se ejecutan por cada fila devuelta.
Oddman el

10

Para encontrar cuántos registros están duplicados en la columna de nombre en Empleado, la consulta a continuación es útil;

Select name from employee group by name having count(*)>1;

10

para obtener todos los datos que contienen duplicación, utilicé esto:

SELECT * FROM TableName INNER JOIN(
  SELECT DupliactedData FROM TableName GROUP BY DupliactedData HAVING COUNT(DupliactedData) > 1 order by DupliactedData)
  temp ON TableName.DupliactedData = temp.DupliactedData;

TableName = la tabla con la que está trabajando.

DupliactedData = los datos duplicados que está buscando.


Este muestra cada duplicado en su propia fila. Eso es lo que necesito. Gracias.
warmwhisky

8

Mi consulta final incorporó algunas de las respuestas que ayudaron: combinar group by, count & GROUP_CONCAT.

SELECT GROUP_CONCAT(id), `magento_simple`, COUNT(*) c 
FROM product_variant 
GROUP BY `magento_simple` HAVING c > 1;

Esto proporciona la identificación de ambos ejemplos (separados por comas), el código de barras que necesitaba y cuántos duplicados.

Cambiar la tabla y las columnas en consecuencia.


8

No veo ningún enfoque JOIN, que tenga muchos usos en términos de duplicados.

Este enfoque le brinda resultados duplicados reales.

SELECT t1.* FROM my_table as t1 
LEFT JOIN my_table as t2 
ON t1.name=t2.name and t1.id!=t2.id 
WHERE t2.id IS NOT NULL 
ORDER BY t1.name

2
FYI: deseará 'seleccionar alguien diferente' si existe la posibilidad de que exista más de 1 registro duplicado; de lo contrario, los resultados contendrán duplicados de las filas duplicadas que se encontraron.
Dibujó el

7
SELECT t.*,(select count(*) from city as tt
  where tt.name=t.name) as count
  FROM `city` as t
  where (
     select count(*) from city as tt
     where tt.name=t.name
  ) > 1 order by count desc

Reemplace la ciudad con su mesa. Reemplace el nombre con el nombre de su campo


7

Tomando la respuesta de @ maxyfc más lejos, necesitaba encontrar todas las filas que fueron devueltas con los valores duplicados, para poder editarlas en MySQL Workbench :

SELECT * FROM table
   WHERE field IN (
     SELECT field FROM table GROUP BY field HAVING count(*) > 1
   ) ORDER BY field

6

Vi el resultado anterior y la consulta funcionará bien si necesita verificar el valor de una sola columna que está duplicado. Por ejemplo correo electrónico.

Pero si necesita verificar con más columnas y desea verificar la combinación del resultado para que esta consulta funcione bien:

SELECT COUNT(CONCAT(name,email)) AS tot,
       name,
       email
FROM users
GROUP BY CONCAT(name,email)
HAVING tot>1 (This query will SHOW the USER list which ARE greater THAN 1
              AND also COUNT)

¡Exactamente lo que se necesitaba! Aquí mi consulta, verificando 3 campos para duplicados:SELECT COUNT(CONCAT(userid,event,datetime)) AS total, userid, event, datetime FROM mytable GROUP BY CONCAT(userid, event, datetime ) HAVING total>1
Kai Noack

4

Prefiero usar funciones de ventana (MySQL 8.0+) para encontrar duplicados porque pude ver toda la fila:

WITH cte AS (
  SELECT *
    ,COUNT(*) OVER(PARTITION BY col_name) AS num_of_duplicates_group
    ,ROW_NUMBER() OVER(PARTITION BY col_name ORDER BY col_name2) AS pos_in_group
  FROM table
)
SELECT *
FROM cte
WHERE num_of_duplicates_group > 1;

DB Fiddle Demo


3
SELECT 
    t.*,
    (SELECT COUNT(*) FROM city AS tt WHERE tt.name=t.name) AS count 
FROM `city` AS t 
WHERE 
    (SELECT count(*) FROM city AS tt WHERE tt.name=t.name) > 1 ORDER BY count DESC

1
Hacer la misma subconsulta dos veces parece ineficiente.
NobleUplift


3
CREATE TABLE tbl_master
    (`id` int, `email` varchar(15));

INSERT INTO tbl_master
    (`id`, `email`) VALUES
    (1, 'test1@gmail.com'),
    (2, 'test2@gmail.com'),
    (3, 'test1@gmail.com'),
    (4, 'test2@gmail.com'),
    (5, 'test5@gmail.com');

QUERY : SELECT id, email FROM tbl_master
WHERE email IN (SELECT email FROM tbl_master GROUP BY email HAVING COUNT(id) > 1)

2
SELECT DISTINCT a.email FROM `users` a LEFT JOIN `users` b ON a.email = b.email WHERE a.id != b.id;

1
Vale la pena señalar que esto es insoportablemente lento o incluso podría no terminar si la columna que se está consultando no está indexada. De lo contrario, yo era capaz de cambiar a.emaila a.*y obtener todos los ID de las filas con duplicados.
NobleUplift

@NobleUplift ¿De qué estás hablando?
Michael

@Michael Bueno, ya que esto tiene tres años, no puedo probar la versión de MySQL que estaba usando, pero intenté esta misma consulta en una base de datos donde la columna que seleccioné no tenía un índice, por lo que tomó bastante tiempo. Unos segundos para terminar. Cambiando a SELECT DISTINCT a.*resuelto casi al instante.
NobleUplift

@NobleUplift Ah, ok. Puedo entender que sea lento ... la parte que me preocupa es "quizás ni siquiera termine".
Michael

@Michael No recuerdo en qué tabla de nuestro sistema tuve que ejecutar esta consulta, pero para aquellos con algunos millones de registros probablemente habrían terminado, pero en un tiempo que tomó tanto tiempo que me di por vencido cuando En realidad terminaría.
NobleUplift

1

Para eliminar filas duplicadas con múltiples campos, primero puede asignarlas a la nueva clave única que se especifica para las únicas filas distintas, luego use el comando "agrupar por" para eliminar filas duplicadas con la misma clave única nueva:

Create TEMPORARY table tmp select concat(f1,f2) as cfs,t1.* from mytable as t1;
Create index x_tmp_cfs on tmp(cfs);
Create table unduptable select f1,f2,... from tmp group by cfs;

¿también puedes agregar una explicación?
Robert

¿Por qué no usar CREATE TEMPORARY TABLE ...? Una pequeña explicación de su solución sería genial.
maxhb

1

Una contribución muy tardía ... en caso de que ayude a alguien muuuucho más adelante ... Tuve la tarea de encontrar pares de transacciones coincidentes (en realidad, ambos lados de las transferencias de cuenta a cuenta) en una aplicación bancaria, para identificar cuáles fueron el 'desde' y el 'hasta' para cada transacción de transferencia entre cuentas, así que terminamos con esto:

SELECT 
    LEAST(primaryid, secondaryid) AS transactionid1,
    GREATEST(primaryid, secondaryid) AS transactionid2
FROM (
    SELECT table1.transactionid AS primaryid, 
        table2.transactionid AS secondaryid
    FROM financial_transactions table1
    INNER JOIN financial_transactions table2 
    ON table1.accountid = table2.accountid
    AND table1.transactionid <> table2.transactionid 
    AND table1.transactiondate = table2.transactiondate
    AND table1.sourceref = table2.destinationref
    AND table1.amount = (0 - table2.amount)
) AS DuplicateResultsTable
GROUP BY transactionid1
ORDER BY transactionid1;

El resultado es que DuplicateResultsTableproporciona filas que contienen transacciones coincidentes (es decir, duplicadas), pero también proporciona los mismos ID de transacción a la inversa la segunda vez que coincide con el mismo par, por lo que el externo SELECTestá allí para agrupar por la primera ID de transacción, lo que se hace usando LEASTy GREATESTpara asegurarse de que los dos transaccionales estén siempre en el mismo orden en los resultados, lo que lo hace seguro para GROUPel primero, eliminando así todas las coincidencias duplicadas. Repasó casi un millón de registros e identificó más de 12,000 coincidencias en poco menos de 2 segundos. Por supuesto, el ID de transacción es el índice primario, lo que realmente ayudó.


1
Select column_name, column_name1,column_name2, count(1) as temp from table_name group by column_name having temp > 1

1
SELECT ColumnA, COUNT( * )
FROM Table
GROUP BY ColumnA
HAVING COUNT( * ) > 1

3
Esto es incorrecto ya que también encuentra ocurrencias únicas. 0 debería ser 1.
Kafoso

1

Si desea eliminar el uso duplicado DISTINCT

De lo contrario, use esta consulta:

SELECT users.*,COUNT(user_ID) as user FROM users GROUP BY user_name HAVING user > 1;


0

Intenta usar esta consulta:

SELECT name, COUNT(*) value_count FROM company_master GROUP BY name HAVING value_count > 1;
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.