2011-05-04 14 views
20

Tengo una tabla que se supone que debe mantener un rastro de visitantes a un perfil determinado (identificación de usuario a par de identificación de usuario). Resultó que mi consulta SQL estaba un poco desajustada y está produciendo varios pares en lugar de los únicos como estaba previsto. En retrospectiva, debería haber impuesto una restricción única en cada par id + id.Eliminar todos menos un registro duplicado

Ahora, ¿cómo podría hacer para limpiar la mesa? Lo que quiero hacer es borrar todos los pares duplicados y dejar solo uno.

Así, por ejemplo, cambiar esta situación:

23515 -> 52525 date_visited 
23515 -> 52525 date_visited 
23515 -> 52525 date_visited 
12345 -> 54321 date_visited 
12345 -> 54321 date_visited 
12345 -> 54321 date_visited 
12345 -> 54321 date_visited 
23515 -> 52525 date_visited 
... 

En esto:

23515 -> 52525 date_visited 
12345 -> 54321 date_visited 

Actualización: Aquí es la estructura de la tabla conforme a lo solicitado:

id int(10)   UNSIGNED Non  Aucun AUTO_INCREMENT 
profile_id int(10)   UNSIGNED Non  0 
visitor_id int(10)   UNSIGNED Non  0 
date_visited timestamp   Non  CURRENT_TIMESTAMP 
+0

¿Cuál es la estructura de la tabla, por favor? ¿Hay una tercera columna para los valores de desempate? – gbn

+0

@gbn: se ha agregado la estructura de la tabla (MySQL). La tercera columna es para mantener un rastro de la última vez que un usuario visitó un perfil. La estructura probablemente debería modificarse con una restricción en profile_id y visitor_id. P.S: No tengo el SQL rellenando la tabla en este momento, pero es algo así como 'si existe una marca de tiempo de actualización si no se crea un registro'. –

Respuesta

36

Familia de uso por en una subconsulta :

delete from my_tab where id not in 
(select min(id) from my_tab group by profile_id, visitor_id); 

Necesita algún tipo de identificador único (aquí, estoy usando el id).

ACTUALIZACIÓN

como señaló @JamesPoulson, esto provoca un error de sintaxis en MySQL; la solución correcta es (como se muestra en James' answer):

delete from `my_tab` where id not in 
(SELECT * FROM 
    (select min(id) from `my_tab` group by profile_id, visitor_id) AS temp_tab 
); 
+1

Gran solución. No había pensado en usar un grupo por (experiencia> conocimiento). Esto muestra un "No se puede especificar el destino en la cláusula FROM", pero hay una solución para esto (ver mi respuesta). –

+2

Tenga en cuenta que esto no funciona en MySQL porque no le permite modificar la tabla que está utilizando en la selección interna: 'Código de error: 1093. No puede especificar la tabla de destino 'my_tab' para la actualización en FROM cláusula ' – Desty

+0

mismo error está aquí. no funciona – VipinS

2

Seleccionar todas las filas únicas
copiarlos a una nueva tabla temporal
truncar la tabla original de
Copiar datos de la tabla temporal de tabla original

Eso es que haría No estoy seguro si hay 1 consulta que haría todo esto por ti.

+0

Usar una tabla temporal es un buen reflejo y en realidad es necesario. Probablemente sea un enfoque más adaptado si hay una gran cantidad de datos. –

12

Aquí está la solución de Frank Schmitt con una pequeña solución para la tabla temporal:

delete from `my_tab` where id not in 
(SELECT * FROM 
    (select min(id) from `my_tab` group by profile_id, visitor_id) AS temp_tab 
) 
+0

@FrankSchmitt está perfectamente bien :) –

1

esto funcionará:

With NewCTE 
AS 
(
Select *, Row_number() over(partition by ID order by ID)as RowNumber from 
table_name 
) 
Delete from NewCTE where RowNumber > 1 
Cuestiones relacionadas