Como borrar registros duplicados de SQL (the ultimate solution)
El dia de hoy en mi trabajo se me presento un problema con registros duplicados de una tabla de SQL server, asi que me di a la tarea que aqueja a todo DBA alguna vez en su vida. Como borrar registros duplicados de una tabla? (yo no soy DBA, por cierto, pero aqui hay que hacerla de todo).
En principio de cuentas, una registro duplicado nos habla de un mal diseño, o de base de datos o de procedimientos. En este caso el problema es un error de procedimiento, pero por ahora no hablaremos de eso.
Mi caso esta asi: Tengo una tabla con ID numerico, y un numero x de campos. De esos campos, los registros duplicados son iguales a excepcion de 1 campo (aparte del ID, por supuesto). La tabla tiene algo mas de 4 millones de registros, y habia unos 400,000 duplicados (algunos mas de 6 veces).
Googleando un poco encontre varias soluciones que van desde hacer un Select distinct a una tabla temporal, vaciar la tabla original y luego copiar lo de la temporal a la original (lo cual resulta muy lento), hasta un script que hacia uso de cursores, y que nunca pude hechar a andar.
Todo fue hasta que por ahi me encontre con una solucion simple, rapida y efectiva, que solo requiere que tu tabla contenga un ID numerico. Si no lo tiene, pues lo puedes agregar facilmente, y si despues no lo requieres, puedes borrarlo.
De lo que se trata es de seleccionar la ID mas baja (o mas alta) de cada conjunto de duplicados (tenemos que definir que es un duplicado), y borrar las demas. Simple, no?
Para ejemplificarlo vamos a suponer que tenemos nuestra tabla “Tabla1″. Esta tabla tiene los campos “ID”, “Campo1″, Campo2″ y “Campo3″. Lo primero que tenemos que hacer es identificar que campos tienen que ser iguales para que un registro sea repetido. Puede ser que sean todos los campos o solo un conjunto de estos. En este ejemplo vamos a decir que Campo2 y 3 son necesarios. Una vez identificados lo que tenemos que hacer es ejecutar la siguiente consulta.
delete from Tabla1 where Id >
(
Select min(Id) from Tabla1 Tbl1 where Tabla1.Campo2 = Tbl1.Campo2 and Tabla1.Campo3 = Tbl1.Campo3
)
Es todo! Simple, no? Funciona igual si cambias el signo por “<” y usas “max” en lugar de “min”. En este caso en lugar de conservar el Id mas baja, conservas la mas alta.
Simple y rapido ademas. Mi consulta demoro poco mas de un minuto en buscar y borrar los duplicados en mi tabla de 4 millones. Espero que esta solucion los salve de mas de una. ∞
January 11th, 2008 at 10:47 am
Excelente solución, mil gracias!!!
February 8th, 2008 at 4:05 pm
excelentisimo, me ayudo bastante
muchas gracias
y felicidades por tu website.
March 4th, 2008 at 11:59 am
a mi me sale error no se porque ,,, porfa ayudam..por ejemplo:
select min(id) from ventas Tv
where
ventas.cliente = Tv.cliente(hay mas columnas pero el error es igual)
no me hace caso y sale error:
Server: Msg 107, Level 16, State 3, Line 1
The column prefix ‘ventas’ does not match with a table name or alias name used in the query.
no compara ni filtra los dup
gracias
June 10th, 2008 at 1:29 am
Esta solución está bien para un caso normal (sin tablas mal diseñadas). La verdad es que es útil y sencillo.
Lo malo es si el campo clave no está definido como tal, y está duplicado también; en ese caso no serviría… y esto pasa a menudo, por desgracia.
Entonces si que tendrás que pasar lo bueno a una tabla temporal, etc.
June 18th, 2008 at 10:08 pm
No, de hecho, sin tablas mal diseñadas, de hecho, no habria necesidad de esto, pues una tabla bien diseñada segun las 3 formas normales, no deberia de tener registros duplicados.
Si hay un campo llave mal definido, pues de hecho es como si no existiera uno. Y la tecnica dice que hay que agregar una nueva columna numerica que nos servira como llave temporal para aplicar esta tecnica
June 26th, 2008 at 2:01 pm
Excelente solución!!!
June 26th, 2008 at 2:02 pm
Excelente solución!!!! Me gustaría saber cuales fueron tus fuentes de consulta para llegar a esto tan simple.
June 26th, 2008 at 8:37 pm
El simple y confiable Google!
August 14th, 2008 at 3:22 pm
Esta solucion funciona, pero!!!!
Si hablaramos de una tabla que tiene un campo clave que se repite y la diferencia de cada registro es una fecha, y solo quisiera dejar los registros sinrepetir con fecha mas alta?
Ya no es tan sencillo verdad?
Si alguien sabe como hacer esto se los agradecere eternamente.
Saludos desde SLP México
August 21st, 2008 at 11:16 am
No, de hecho es exactamente lo mismo. Lo unico que tienes que hacer es agregar otro campo a la tabla, autonumerico para asegurarte que sea unico, y basar en el el borrado de duplicados.
August 21st, 2008 at 11:37 am
Exelente solucion.
Aunque no la utilice para eliminar si no para hacer una consulta
igual se agradece, me sirvio mucho
October 10th, 2008 at 11:29 am
muchas gracias, realamente me ayudo bastante
November 11th, 2008 at 3:01 am
Perfecto!!! me has ayudado mucho, también había encontrado la solcuión de la tabla temporal, pero como que no, era demasiado complicado, ésta sin embargo es…. tan simple…
November 22nd, 2008 at 10:42 am
se pueden apoyar de rowid como campo clave, este segun yo no se repite