2011-08-02 10 views
7

Tengo una tabla que tiene un índice único no agrupado y 4 de las columnas se enumeran en este índice. Quiero actualizar una gran cantidad de filas en la tabla. Si lo hago, ya no serán distintos, por lo tanto, la actualización falla debido al índice.Supresión de filas no distintas

Quiero deshabilitar el índice y luego eliminar las filas duplicadas más antiguas. Aquí está mi consulta hasta el momento:

SELECT t.itemid, t.fieldid, t.version, updated 
FROM dbo.VersionedFields w 
inner JOIN 
(
    SELECT itemid, fieldid, version, COUNT(*) AS QTY 
    FROM dbo.VersionedFields 
    GROUP BY itemid, fieldid, version 
    HAVING COUNT(*) > 1 
) t 
on w.itemid = t.itemid and w.fieldid = t.fieldid and w.version = t.version 

El selecto dentro de la unión interna devuelve el número correcto de registros que se quieren eliminar, pero los agrupa por lo que no es en realidad el doble de la cantidad.

Después de la unión, muestra todos los registros pero todo lo que quiero eliminar son los más antiguos?

¿Cómo se puede hacer esto?

Respuesta

9

Si dice SQL (Structured Query Language), pero realmente decir SQL Server (el sistema de base de datos Microsoft relatinonal) por él, y si está utilizando SQL Server 2005 o posterior, puede utilizar un CTE (expresión de tabla común) para este propósito.

Con este CTE, puede dividir sus datos según algunos criterios, es decir, su ItemId (o una combinación de columnas) y tener todas las filas del servidor SQL en 1 para cada una de esas particiones, ordenadas por otros criterios - es decir, probablemente version (o alguna otra columna).

Así que trate de algo como esto:

;WITH PartitionedData AS 
(
    SELECT 
     itemid, fieldid, version, 
     ROW_NUMBER() OVER(PARTITION BY ItemId ORDER BY version DESC) AS 'RowNum' 
    FROM dbo.VersionedFields 
) 
DELETE FROM PartitionedData 
WHERE RowNum > 1 

Básicamente, estás partición de los datos por parte de algunos criterios y numeración de cada partición, a partir de 1 de cada nueva partición, ordenada por algunos otros criterios (por ejemplo, fecha o Versión).

Por lo tanto, para cada "partición" de datos, la entrada "más nueva" tiene RowNum = 1, y cualquier otra que pertenezca a la misma partición (por tener los mismos valores de partitino) tendrá valores numerados secuencialmente desde 2 hasta a cuantas filas hay en esa partición.

Si desea conservar solo la entrada más reciente, elimine todo lo que tenga un RowNum mayor que 1 y listo.

4

En SQL Server 2005 y superiores:

WITH q AS 
     (
     SELECT *, 
       ROW_NUMBER() OVER (PARTITION BY itemid, fieldid, version ORDER BY updated DESC) AS rn 
     FROM versionedFields 
     ) 
DELETE 
FROM q 
WHERE rn > 1 
0

Pruebe algo como:

DELETE FROM dbo.VersionedFields w WHERE w.version < (SELECT MAX(version) FROM dbo.VersionedFields) 

Por supuesto, usted desea limitar el MAX (versión) para sólo las versiones del campo que está queriendo borrar

0

Probablemente necesite mirar this Stack Overflow answer (elimine antes de las filas duplicadas).

Básicamente, la técnica utiliza la agrupación (u opcionalmente, creación de ventanas) para encontrar el valor mínimo de identificación de un grupo para eliminarlo. Puede ser más preciso eliminar filas donde el valor <> max (identificador de fila).

Así:

  1. gota índice único
  2. Cargar datos
  3. eliminar los datos utilizando el mecanismo de agrupación (idealmente en una transacción, por lo que se puede deshacer si hay un error), a continuación se comprometen
  4. Recrear el índice.

Tenga en cuenta que la recreación de un índice en una mesa grande puede llevar mucho tiempo.

+1

La solución de marc_s es una manera elegante de hacerlo. – rorycl

Cuestiones relacionadas