valores traer seleccionar registros mostrar filas duplicados duplicadas datos consultar buscar mysql sql duplicates

traer - Eliminar filas duplicadas en MySQL



select mysql registros duplicados (17)

Tengo una tabla con los siguientes campos:

id (Unique) url (Unique) title company site_id

Ahora, necesito eliminar las filas que tienen el mismo title, company and site_id . Una forma de hacerlo será utilizando el siguiente SQL junto con un script ( PHP ):

SELECT title, site_id, location, id, count( * ) FROM jobs GROUP BY site_id, company, title, location HAVING count( * ) >1

Después de ejecutar esta consulta, puedo eliminar duplicados utilizando una secuencia de comandos del lado del servidor.

Pero, quiero saber si esto se puede hacer sólo mediante la consulta SQL.


Elimine filas duplicadas utilizando la declaración DELETE JOIN MySQL le proporciona la instrucción DELETE JOIN que puede usar para eliminar filas duplicadas rápidamente.

La siguiente declaración elimina filas duplicadas y mantiene el ID más alto:

DELETE t1 FROM contacts t1 INNER JOIN contacts t2 WHERE t1.id < t2.id AND t1.email = t2.email;


Esta solución moverá los duplicados a una tabla y los únicos a otra .

-- speed up creating uniques table if dealing with many rows CREATE INDEX temp_idx ON jobs(site_id, company, title, location); -- create the table with unique rows INSERT jobs_uniques SELECT * FROM ( SELECT * FROM jobs GROUP BY site_id, company, title, location HAVING count(1) > 1 UNION SELECT * FROM jobs GROUP BY site_id, company, title, location HAVING count(1) = 1 ) x -- create the table with duplicate rows INSERT jobs_dupes SELECT * FROM jobs WHERE id NOT IN (SELECT id FROM jobs_uniques) -- confirm the difference between uniques and dupes tables SELECT COUNT(1) AS jobs, (SELECT COUNT(1) FROM jobs_dupes) + (SELECT COUNT(1) FROM jobs_uniques) AS sum FROM jobs


Hay otra solución:

DELETE t1 FROM my_table t1, my_table t2 WHERE t1.id < t2.id AND t1.my_field = t2.my_field AND t1.my_field_2 = t2.my_field_2 AND ...


La eliminación de duplicados en las tablas de MySQL es un problema común, que generalmente es el resultado de una restricción que falta para evitar esos duplicados de antemano. Pero este problema común generalmente viene con necesidades específicas ... que requieren enfoques específicos. El enfoque debe ser diferente según, por ejemplo, el tamaño de los datos, la entrada duplicada que se debe conservar (generalmente la primera o la última), si hay que mantener índices o si queremos realizar algún análisis adicional. Acción sobre los datos duplicados.

También hay algunas especificidades en MySQL, como no poder hacer referencia a la misma tabla en una causa DESDE al realizar una ACTUALIZACIÓN de tabla (generará el error de MySQL # 1093). Esta limitación se puede superar mediante el uso de una consulta interna con una tabla temporal (como se sugiere en algunos enfoques anteriores). Pero esta consulta interna no funcionará especialmente bien cuando se trata de fuentes de datos grandes.

Sin embargo, existe un mejor enfoque para eliminar duplicados, que es a la vez eficiente y confiable, y que se puede adaptar fácilmente a diferentes necesidades.

La idea general es crear una nueva tabla temporal, generalmente agregando una restricción única para evitar duplicados adicionales, e INSERTAR los datos de su tabla anterior en la nueva, mientras cuida los duplicados. Este enfoque se basa en consultas sencillas de MySQL INSERT, crea una nueva restricción para evitar duplicados adicionales, y omite la necesidad de usar una consulta interna para buscar duplicados y una tabla temporal que debe mantenerse en la memoria (por lo tanto, también se ajustan las fuentes de datos grandes).

Así es como se puede lograr. Dado que tenemos un empleado de mesa, con las siguientes columnas:

employee (id, first_name, last_name, start_date, ssn)

Para eliminar las filas con una columna ssn duplicada y mantener solo la primera entrada encontrada, se puede seguir el siguiente proceso:

-- create a new tmp_eployee table CREATE TABLE tmp_employee LIKE employee; -- add a unique constraint ALTER TABLE tmp_employee ADD UNIQUE(ssn); -- scan over the employee table to insert employee entries INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id; -- rename tables RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

Explicacion tecnica

  • La línea # 1 crea una nueva tabla tmp_eployee con exactamente la misma estructura que la tabla de empleados
  • La línea # 2 agrega una restricción ÚNICA a la nueva tabla tmp_eployee para evitar más duplicados
  • La línea # 3 explora la tabla de empleados original por ID, insertando nuevas entradas de empleados en la nueva tabla tmp_eployee , mientras ignora las entradas duplicadas
  • La línea # 4 renombra las tablas, de modo que la nueva tabla de empleados contiene todas las entradas sin los duplicados, y una copia de respaldo de los datos anteriores se mantiene en la tabla backup_employee

Usando este enfoque, los registros 1.6M se convirtieron en 6k en menos de 200s.

, siguiendo este proceso, podría eliminar rápida y fácilmente todos sus duplicados y crear una restricción ÚNICA ejecutando:

CREATE TABLE tmp_jobs LIKE jobs; ALTER TABLE tmp_jobs ADD UNIQUE(site_id, title, company); INSERT IGNORE INTO tmp_jobs SELECT * FROM jobs ORDER BY id; RENAME TABLE jobs TO backup_jobs, tmp_jobs TO jobs;

Por supuesto, este proceso puede modificarse aún más para adaptarlo a diferentes necesidades al eliminar duplicados. Algunos ejemplos siguen.

✔ Variación para mantener la última entrada en lugar de la primera.

A veces necesitamos mantener la última entrada duplicada en lugar de la primera.

CREATE TABLE tmp_employee LIKE employee; ALTER TABLE tmp_employee ADD UNIQUE(ssn); INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id DESC; RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

  • En la línea # 3, la cláusula ORDER BY id DESC hace que las últimas ID obtengan prioridad sobre el resto

✔ Variación para realizar algunas tareas en los duplicados, por ejemplo, manteniendo un recuento en los duplicados encontrados

A veces necesitamos realizar un procesamiento adicional en las entradas duplicadas que se encuentran (como mantener un recuento de los duplicados).

CREATE TABLE tmp_employee LIKE employee; ALTER TABLE tmp_employee ADD UNIQUE(ssn); ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0; INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1; RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

  • En la línea # 3, se crea una nueva columna n_duplicates
  • En la línea # 4, la consulta INSERT INTO ... ON DUPLICATE KEY UPDATE se utiliza para realizar una actualización adicional cuando se encuentra un duplicado (en este caso, un contador). La consulta INSERT INTO ... ON DUPLICATE KEY UPDATE puede ser Se utiliza para realizar diferentes tipos de actualizaciones para los duplicados encontrados.

✔ Variación para regenerar la identificación de campo auto-incremental

Algunas veces usamos un campo auto-incremental y, para mantener el índice lo más compacto posible, podemos aprovechar la eliminación de los duplicados para regenerar el campo auto-incremental en la nueva tabla temporal.

CREATE TABLE tmp_employee LIKE employee; ALTER TABLE tmp_employee ADD UNIQUE(ssn); INSERT IGNORE INTO tmp_employee SELECT (first_name, last_name, start_date, ssn) FROM employee ORDER BY id; RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

  • En la línea # 3, en lugar de seleccionar todos los campos de la tabla, el campo de identificación se omite para que el motor DB genere uno nuevo automáticamente.

✔ variaciones adicionales

Muchas modificaciones adicionales también son factibles dependiendo del comportamiento deseado. Como ejemplo, las siguientes consultas utilizarán una segunda tabla temporal para, además de 1) mantener la última entrada en lugar de la primera; y 2) aumentar un contador en los duplicados encontrados; también 3) regenera la identificación de campo auto-incremental mientras se mantiene el orden de entrada como estaba en los datos anteriores.

CREATE TABLE tmp_employee LIKE employee; ALTER TABLE tmp_employee ADD UNIQUE(ssn); ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0; INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id DESC ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1; CREATE TABLE tmp_employee2 LIKE tmp_employee; INSERT INTO tmp_employee2 SELECT (first_name, last_name, start_date, ssn) FROM tmp_employee ORDER BY id; DROP TABLE tmp_employee; RENAME TABLE employee TO backup_employee, tmp_employee2 TO employee;


La forma más rápida es insertar filas distintas en una tabla temporal. Usando la opción de borrar, me tomó algunas horas eliminar los duplicados de una tabla de 8 millones de filas. Utilizando inserto y distinto, solo tardó 13 minutos.

CREATE TABLE tempTableName LIKE tableName; CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value); INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName; TRUNCATE TABLE tableName; INSERT INTO tableName SELECT * FROM tempTableName; DROP TABLE tempTableName;


Me gusta ser un poco más específico en cuanto a qué registros borro, así que aquí está mi solución:

delete from jobs c1 where not c1.location = ''Paris'' and c1.site_id > 64218 and exists ( select * from jobs c2 where c2.site_id = c1.site_id and c2.company = c1.company and c2.location = c1.location and c2.title = c1.title and c2.site_id > 63412 and c2.site_id < 64219 )


MySQL tiene restricciones para referirse a la tabla de la que está eliminando. Puedes solucionar esto con una tabla temporal, como:

create temporary table tmpTable (id int); insert tmpTable (id) select id from YourTable yt where exists ( select * from YourTabe yt2 where yt2.title = yt.title and yt2.company = yt.company and yt2.site_id = yt.site_id and yt2.id > yt.id ); delete from YourTable where ID in (select id from tmpTable);

De la sugerencia de Kostanos en los comentarios:
La única consulta lenta anterior es DELETE, para los casos en los que tiene una base de datos muy grande. Esta consulta podría ser más rápida:

DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id


Puede eliminar fácilmente los registros duplicados de este código ...

$qry = mysql_query("SELECT * from cities"); while($qry_row = mysql_fetch_array($qry)) { $qry2 = mysql_query("SELECT * from cities2 where city = ''".$qry_row[''city'']."''"); if(mysql_num_rows($qry2) > 1){ while($row = mysql_fetch_array($qry2)){ $city_arry[] = $row; } $total = sizeof($city_arry) - 1; for($i=1; $i<=$total; $i++){ mysql_query( "delete from cities2 where town_id = ''".$city_arry[$i][0]."''"); } } //exit; }


Sencillo y rápido para todos los casos:

CREATE TEMPORARY TABLE IF NOT EXISTS _temp_duplicates AS (SELECT dub.id FROM table_with_duplications dub GROUP BY dub.field_must_be_uniq_1, dub.field_must_be_uniq_2 HAVING COUNT(*) > 1); DELETE FROM table_with_duplications WHERE id IN (SELECT id FROM _temp_duplicates);


Si la declaración IGNORE no funciona como en mi caso, puede usar la siguiente declaración:

CREATE TABLE your_table_deduped like your_table; INSERT your_table_deduped SELECT * FROM your_table GROUP BY index1_id, index2_id; RENAME TABLE your_table TO your_table_with_dupes; RENAME TABLE your_table_deduped TO your_table; #OPTIONAL ALTER TABLE `your_table` ADD UNIQUE `unique_index` (`index1_id`, `index2_id`); #OPTIONAL DROP TABLE your_table_with_dupes;


Si no desea modificar las propiedades de la columna, puede utilizar la consulta a continuación.

Como tiene una columna que tiene ID únicos (por ejemplo, columnas auto_increment ), puede usarla para eliminar los duplicados:

DELETE `a` FROM `jobs` AS `a`, `jobs` AS `b` WHERE -- IMPORTANT: Ensures one version remains -- Change "ID" to your unique column''s name `a`.`ID` < `b`.`ID` -- Any duplicates you want to check for AND (`a`.`title` = `b`.`title` OR `a`.`title` IS NULL AND `b`.`title` IS NULL) AND (`a`.`company` = `b`.`company` OR `a`.`company` IS NULL AND `b`.`company` IS NULL) AND (`a`.`site_id` = `b`.`site_id` OR `a`.`site_id` IS NULL AND `b`.`site_id` IS NULL);

En MySQL, puedes simplificarlo aún más con el operador igual de seguro NULL (también conocido como "operador de nave espacial" ):

DELETE `a` FROM `jobs` AS `a`, `jobs` AS `b` WHERE -- IMPORTANT: Ensures one version remains -- Change "ID" to your unique column''s name `a`.`ID` < `b`.`ID` -- Any duplicates you want to check for AND `a`.`title` <=> `b`.`title` AND `a`.`company` <=> `b`.`company` AND `a`.`site_id` <=> `b`.`site_id`;


Si tiene una tabla grande con un gran número de registros, las soluciones anteriores no funcionarán o tomarán demasiado tiempo. Entonces tenemos una solución diferente.

-- Create temporary table CREATE TABLE temp_table LIKE table1; -- Add constraint ALTER TABLE temp_table ADD UNIQUE(title, company,site_id); -- Copy data INSERT IGNORE INTO temp_table SELECT * FROM table1; -- Rename and drop RENAME TABLE table1 TO old_table1, temp_table TO table1; DROP TABLE old_table1;


Sigo visitando esta página cada vez que busco en Google "eliminar duplicados de mysql", pero para mi las soluciones de THEIGNORE no funcionan porque tengo tablas de mysql de InnoDB

este código funciona mejor en cualquier momento

CREATE TABLE tableToclean_temp LIKE tableToclean; ALTER TABLE tableToclean_temp ADD UNIQUE INDEX (fontsinuse_id); INSERT IGNORE INTO tableToclean_temp SELECT * FROM tableToclean; DROP TABLE tableToclean; RENAME TABLE tableToclean_temp TO tableToclean;

tableToclean = el nombre de la tabla que necesitas limpiar

tableToclean_temp = una tabla temporal creada y eliminada


Tengo este snipet de consulta para SQLServer pero creo que se puede usar en otros DBMS con pequeños cambios:

DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM idTable GROUP BY field1, field2, field3 HAVING COUNT(*) > 1)

Olvidé decirle que esta consulta no elimina la fila con el ID más bajo de las filas duplicadas. Si esto funciona para usted intente esta consulta:

DELETE FROM jobs WHERE jobs.id IN ( SELECT MAX(id) FROM jobs GROUP BY site_id, company, title, location HAVING COUNT(*) > 1)


Tuve que hacer esto con los campos de texto y encontré el límite de 100 bytes en el índice.

Resolví esto agregando una columna, haciendo un hash md5 de los campos y haciendo el cambio.

ALTER TABLE table ADD `merged` VARCHAR( 40 ) NOT NULL ; UPDATE TABLE SET merged` = MD5(CONCAT(`col1`, `col2`, `col3`)) ALTER IGNORE TABLE table ADD UNIQUE INDEX idx_name (`merged`);


Una forma realmente fácil de hacer esto es agregar un índice UNIQUE en las 3 columnas. Cuando escriba la instrucción ALTER , incluya la IGNORE clave IGNORE . Al igual que:

ALTER IGNORE TABLE jobs ADD UNIQUE INDEX idx_name (site_id, title, company);

Esto eliminará todas las filas duplicadas. Como un beneficio adicional, los futuros INSERTs que son duplicados producirán un error. Como siempre, es posible que desee realizar una copia de seguridad antes de ejecutar algo como esto ...


Una solución que es fácil de entender y funciona sin clave principal:

1) agregar una nueva columna booleana

alter table mytable add tokeep boolean;

2) agregar una restricción en las columnas duplicadas Y la nueva columna

alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);

3) establece la columna booleana en verdadero. Esto solo tendrá éxito en una de las filas duplicadas debido a la nueva restricción

update ignore mytable set tokeep = true;

4) eliminar filas que no han sido marcadas como tokeep

delete from mytable where tokeep is null;

5) soltar la columna añadida

alter table mytable drop tokeep;

Le sugiero que mantenga la restricción que agregó, para evitar nuevos duplicados en el futuro.