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?

Jon Tackabury
fuente
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.

levik
fuente
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;
maxyfc
fuente
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.

Quassnoi
fuente
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;
Matt Rardon
fuente
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.

TechTravelThink
fuente
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)
Strustam
fuente
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;
usuario5599549
fuente
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.

udi
fuente
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.

Jonathan
fuente
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
Adam Fischer
fuente
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

Lalit Patel
fuente
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
Cero absoluto
fuente
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)
davejal
fuente
¡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

Lukasz Szozda
fuente
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
magesh
fuente
1
Hacer la misma subconsulta dos veces parece ineficiente.
NobleUplift
2
SELECT DISTINCT a.email FROM `users` a LEFT JOIN `users` b ON a.email = b.email WHERE a.id != b.id;
Pawel Furmaniak
fuente
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;
irshst
fuente
¿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ó.

Fortyninthnet
fuente
1
Select column_name, column_name1,column_name2, count(1) as temp from table_name group by column_name having temp > 1
Vipin Jain
fuente
1
SELECT ColumnA, COUNT( * )
FROM Table
GROUP BY ColumnA
HAVING COUNT( * ) > 1
Scott Ferguson
fuente
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;

Hassan Latif Butt
fuente
0

Intenta usar esta consulta:

SELECT name, COUNT(*) value_count FROM company_master GROUP BY name HAVING value_count > 1;
Atul Akabari
fuente