2011-11-08 29 views
47

Estoy tratando de eliminar duplicados de una tabla MySQL utilizando ALTER IGNORE TABLE + una clave única. La documentación de MySQL dice:MySQL: ALTER IGNORE TABLE da "Integrity constraint violation"

IGNORE es una extensión de MySQL para SQL estándar. Controla cómo funciona ALTER TABLE si hay duplicados en claves únicas en la nueva tabla o si se producen advertencias cuando se habilita el modo estricto. Si no se especifica IGNORE, la copia se cancela y se retrotrae si se producen errores de clave duplicada. Si se especifica IGNORE, solo se usa la primera fila de filas con duplicados en una clave única. Las otras filas conflictivas se eliminan. Los valores incorrectos se truncan al valor aceptable de coincidencia más cercano.

Cuando ejecuto la consulta ...

ALTER IGNORE TABLE table ADD UNIQUE INDEX dupidx (field) 

... sigo teniendo el error # 1062 - Duplicar entrada 'blabla' para la llave 'dupidx'.

Respuesta

95

La extensión de palabra clave IGNORE para MySQL parece tener un bug in the InnoDB version en alguna versión de MySQL.

Siempre se puede, convertir a MyISAM, hacer caso omiso a agregar el índice y luego convertir de nuevo a InnoDB

ALTER TABLE table ENGINE MyISAM; 
ALTER IGNORE TABLE table ADD UNIQUE INDEX dupidx (field); 
ALTER TABLE table ENGINE InnoDB; 

Nota, si usted tiene restricciones de clave externa, esto no funciona, usted tendrá que quitar los primero y añádelos más tarde.

+56

En ese enlace al error InnoDB hay una solución sugerida para la primera carrera 'set sesión old_alter_table = 1;' Esto funcionó para! yo. – Peter

+1

Gracias Peter - esto parece estar funcionando para mí ahora. No tenía idea de este problema: mi máquina de desarrollo es Mariadb, pero cuando tuve que ejecutar la producción (mysql 5.5) tropecé con esto. ¡Este stackoverflow salvó mi día! – spidie

+5

Esta es posiblemente la peor respuesta aceptada que he visto en Stack Overflow. Cambiar los motores de almacenamiento es una tarea significativa en sí misma, incluso con tablas de tamaño mediano. Estas tres consultas podrían bloquear un servidor de base de datos durante horas. Esto no es nada como una solución. – Mikkel

2

El problema es que tiene datos duplicados en el campo que intenta indexar. Tendrá que eliminar los duplicados ofensivos antes de poder agregar un índice único.

Una forma es hacer lo siguiente:

CREATE TABLE tmp_table LIKE table; 
    ALTER IGNORE TABLE tmp_table ADD UNIQUE INDEX dupidx (field); 
    INSERT IGNORE INTO tmp_table SELECT * FROM table; 
    DROP TABLE table; 
    RENAME TABLE tmp_table TO table; 

esto le permite insertar solamente los datos únicos en la tabla

+0

No, la palabra clave IGNORE debe encargarse de esos duplicados. Esa sería la belleza de esta solución. Ver los documentos citados en mi pregunta. –

25

O intenta establecer la sesión old_alter_table = 1 (No se olvide de configurarlo espalda)

Ver: http://mysqlolyk.wordpress.com/2012/02/18/alter-ignore-table-add-index-always-give-errors/

+2

Esto funcionó para mí. Es largo en mesas grandes, pero parece bastante lineal. En mi máquina, fue capaz de procesar aproximadamente 2GiB de datos por hora, que fue de aproximadamente dos días. Me pregunto cómo se compara con la solución aceptada, que era convertir a myISAM, agregar el índice y convertir de nuevo. –

+0

¡Ten cuidado! Si está utilizando la replicación, la configuración 'old_alter_table' no se replica, por lo que' ALTER TABLE IGNORE' fallará en el esclavo y romperá la replicación.Para arreglar esto, realicé el 'ALTER' manualmente en el esclavo, luego salté el delincuente' ALTER TABLE' usando 'SET GLOBAL sql_slave_skip_counter = 1', luego reanudé la replicación. – thenickdude

Cuestiones relacionadas