2010-02-09 14 views
25

He visto un par de soluciones para esto, pero me pregunto cuál es la mejor y más eficiente manera de desviar una mesa. Puedes usar código (SQL, etc.) para ilustrar tu punto, pero solo estoy buscando algoritmos básicos. Supuse que ya habría una pregunta sobre esto en SO, pero no pude encontrar ninguna, así que si ya existe, solo denme una alerta.¿Cuál es la mejor manera de deducir una mesa?

(Solo para aclarar - Me refiero a la eliminación de duplicados en una tabla que tiene una PK incremental automática y tiene algunas filas que están duplicados en todo, pero el campo de PK.)

+0

¿Se refiere a duplicados * idénticos * duplicados (a excepción de PK), o colapsando * suficientemente similares * duplicados? El primero se puede hacer de manera bastante directa, este último es un mundo potencial de incertidumbre y dolor. –

+0

@j_random_hacker - Quise decir completamente idéntico. Vea la redacción de la publicación - "Me refiero a deshacerse de duplicados ... filas que son duplicados en * todo menos el campo PK *". – froadie

+0

Lo siento, no leí con cuidado ... –

Respuesta

1

Se podría generar una hash para cada fila (excluyendo PK), almacénelo en una nueva columna (o si no puede agregar nuevas columnas, ¿puede mover la tabla a un área de transición temporal?), y luego busque todas las demás filas con la misma picadillo. Por supuesto, debería poder asegurarse de que su función hash no produzca el mismo código para diferentes filas.

Si dos filas están duplicadas, ¿importa de qué deshacerse? ¿Es posible que otros datos dependan de los dos duplicados? Si es así, tendrá que pasar por unos pocos pasos:

  • Encuentra los incautos
  • elegir uno de ellos como dupeA para eliminar
  • Encuentra todos los datos que dependen de dupeA
  • Alter que los datos que se refieren a dupeB
  • eliminar dupeA.

Esto podría ser fácil o complicado, dependiendo de su modelo de datos existente.

Todo este escenario parece un proyecto de mantenimiento y rediseño. Si es así, ¡mucha suerte!

+0

cómo exactamente te aseguras de que hashes don Produce el mismo código para diferentes datos. Cuando se usan hashes, siempre hay una posibilidad para los incautos. Voto abajo. –

+0

@EsbenP: He visto cadenas comprimidas usadas como una especie de hash para las cadenas originales. Al menos no te engañan. – FrustratedWithFormsDesigner

+0

Asumí que ningún otro dato depende del campo PK. Pero ese es un punto interesante: ¿qué harías si fuera así? Eso lo haría mucho más complicado ... ¿Alguna idea? – froadie

0

Para SQL, puede usar la tabla INSERT IGNORE INTO SELECT xy FROM unkeyed_table;

Para un algoritmo, si puede suponer que las claves para ser primarias se pueden repetir, pero una clave principal para identificar de forma única el contenido de la fila, entonces hash solo la clave para ser primaria y verificar la repetición.

0

Creo que esto no debería requerir nada más que simplemente agrupar por todas las columnas excepto el ID y elegir una fila de cada grupo - por simplicidad solo la primera fila, pero esto no importa además de que tienes restricciones adicionales en la identificación.

O al revés para deshacerse de las filas ... simplemente elimine todas las filas acepte una sola de todos los grupos.

7

SELECT DISTINCT <insert all columns but the PK here> FROM foo. Cree una tabla temporal usando esa consulta (la sintaxis varía según RDBMS pero normalmente hay un patrón SELECT … INTO o CREATE TABLE AS disponible), luego elimine la tabla anterior y extraiga los datos de la tabla temporal.

8

Deduping raramente es simple. Esto se debe a que los registros a desduplicar a menudo tienen valores ligeramente diferentes en algunos de los campos. Por lo tanto, elegir qué registro conservar puede ser problemático. Además, los dúos son a menudo registros de personas y es difícil identificar si los dos John Smith son dos personas o una persona que está duplicada. Así que gasta mucho (50% o más de todo el proyecto) de tu tiempo definiendo qué constituye un dup y cómo manejar las diferencias y los registros de los niños.

¿Cómo sabes cuál es el valor correcto? Dedupping adicional requiere que usted maneje todos los registros secundarios que no estén huérfanos. Lo que sucede cuando descubres que al cambiar la identificación en el registro secundario violas de repente uno de los índices o restricciones únicos, esto sucederá eventualmente y tu proceso debe manejarlo. Si ha elegido estúpidamente aplicar todas sus restricciones solo a través de la aplicación, es posible que ni siquiera sepa que las restricciones son violadas. Cuando tiene 10,000 registros para deduplicar, no va a ir a través de la aplicación para deduplicar uno a la vez. Si la restricción no está en la base de datos, mucha suerte en mantener la integridad de los datos cuando deduplicas.

Una complicación adicional es que los dups no siempre coinciden exactamente en el nombre o la dirección. Por ejemplo, un vendedor llamado Joan Martin puede ser un duplicado de un representante de ventas llamado Joan Martin-Jones, especialmente si tienen la misma dirección y correo electrónico. O podrías tener a John o Johnny en el nombre. O la misma dirección, excepto un registro abreviado ST. y uno deletreó Street. En el servidor SQL puede usar SSIS y agrupamiento difuso para identificar también coincidencias cercanas. Estos son a menudo los dúos más comunes ya que el hecho de que no fueron coincidencias exactas es el motivo por el cual se pusieron como dúas en primer lugar.

Para algunos tipos de deduplicación, es posible que necesite una interfaz de usuario, de modo que la persona que realiza la deduplicación pueda elegir cuál de los dos valores usar para un campo en particular. Esto es especialmente cierto si la persona que está siendo dedupped está en dos o más roles. Podría ser que los datos para un rol en particular usualmente son mejores que los datos para otro rol. O podría ser que solo los usuarios sabrán a ciencia cierta cuál es el valor correcto o pueden necesitar ponerse en contacto con personas para averiguar si realmente son dúplex o simplemente dos personas con el mismo nombre.

1

Para aquellos de ustedes que prefieren un enfoque rápido y sucio, simplemente una lista de todas las columnas que en conjunto definen un registro único y crear un índice único con esas columnas, así:

ALTER IGNORE TABLA TABLE_NAME ADD único (column1, column2, column3)

Puede soltar las contraseñas de índice único.

3

Aquí está el método que utilizo si usted puede conseguir sus criterios de duplicados en un grupo por la afirmación y la tabla tiene una columna de identidad ID de singularidad:

delete t 
from tablename t 
inner join 
(
    select date_time, min(id) as min_id 
    from tablename 
    group by date_time 
    having count(*) > 1 
) t2 on t.date_time = t2.date_time 
where t.id > t2.min_id 

En este ejemplo, el fecha_hora es el criterio de agrupación, si tiene más de una columna, asegúrese de unirse a todas ellas.

+0

me gusta este. Acabo de probarlo y funciona muy bien para mí. –

+0

¡Solución fantástica! ¡Gracias! –

1

Estoy tomando el de DShook y proporciono un ejemplo de dedupe en el que solo conservaría el registro con la fecha más alta.

En este ejemplo decir que tengo 3 registros de todos con el mismo APP_ID, y sólo quieren mantener el uno con la fecha más alto:

DELETE t 
FROM @USER_OUTBOX_APPS t 
INNER JOIN 
(
    SELECT 
     app_id 
     ,max(processed_date) as max_processed_date 
    FROM @USER_OUTBOX_APPS 
    GROUP BY app_id 
    HAVING count(*) > 1 
) t2 on 
    t.app_id = t2.app_id 
WHERE 
    t.processed_date < t2.max_processed_date 
0

Esto puede deduplicar los valores duplicados en c1:

select * from foo 
minus 
select f1.* from foo f1, foo f2 
where f1.c1 = f2.c1 and f1.c2 > f2.c2 
7

Usando función analítica row_number:

WITH CTE (col1, col2, dupcnt) 
AS 
(
SELECT col1, col2, 
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col1) AS dupcnt 
FROM Youtable 
) 
DELETE 
FROM CTE 
WHERE dupcnt > 1 
GO                 
0

Aquí hay uno Me encontré con, en la vida real.

Supongamos que tiene una tabla de inicios de sesión externos/de terceros para los usuarios, y fusionará dos usuarios y desea deducir los valores de clave del proveedor/proveedor.

;WITH Logins AS 
    (
     SELECT [LoginId],[UserId],[Provider],[ProviderKey] 
     FROM [dbo].[UserLogin] 
     WHERE [UserId][email protected] -- is the user we're deleting 
       OR [UserId][email protected] -- is the user we're moving data to 
    ), Ranked AS 
    (
     SELECT Logins.* 
      , [Picker]=ROW_NUMBER() OVER (
         PARTITION BY [Provider],[ProviderKey] 
         ORDER BY CASE WHEN [UserId][email protected] THEN 1 ELSE 0 END) 
     FROM Logins 
    ) 
    MERGE Logins AS T 
    USING Ranked AS S 
    ON S.[LoginId]=T.[LoginID] 
    WHEN MATCHED AND S.[Picker]>1 -- duplicate Provider/ProviderKey 
       AND T.[UserID][email protected] -- safety check 
    THEN DELETE 
    WHEN MATCHED AND S.[Picker]=1 -- the only or best one 
       AND T.[UserID][email protected] 
    THEN UPDATE SET T.[UserID][email protected] 
    OUTPUT $action, DELETED.*, INSERTED.*; 
5

Añadiendo el código real aquí para referencia futura

Por lo tanto, hay 3 pasos, y por lo tanto 3 sentencias SQL:

Paso 1: Mueva los no duplicados (tuplas únicas) en un temporal tabla

CREATE TABLE new_table as 
SELECT * FROM old_table WHERE 1 GROUP BY [column to remove duplicates by]; 

Paso 2: eliminar la tabla de edad (o cambiarle el nombre) ya no necesitamos la mesa con todas las entradas duplicadas, por lo que caer!

DROP TABLE old_table; 

Paso 3: cambie el nombre del new_table al nombre de la old_table

RENAME TABLE new_table TO old_table; 

Y, por supuesto, no se olvide de fijar su código erróneo para detener la inserción de los duplicados!

0

Estos métodos funcionarán, pero sin una identificación explícita como PK, entonces determinar qué filas eliminar podría ser un problema. El rebote en una tabla temporal eliminar del original y volver a insertar sin los engaños parece ser el más simple.

Cuestiones relacionadas