2011-08-02 12 views
7

Ho una tabella con un indice univoco non cluster e 4 delle colonne sono elencate in questo indice. Voglio aggiornare un numero elevato di righe nella tabella. Se lo faccio, non saranno più distinti, quindi l'aggiornamento fallirà a causa dell'indice.Eliminazione di righe non distinte

Desidero disattivare l'indice e quindi eliminare le righe duplicate meno recenti. Ecco la mia domanda finora:

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 

Il selezionare all'interno della inner join restituisce il giusto numero di record che si desidera eliminare, ma i gruppi in modo v'è in realtà il doppio della quantità.

Dopo l'unione mostra tutti i record ma tutti quelli che voglio eliminare sono quelli più vecchi?

Come si può fare?

risposta

9

Se dici SQL (Structured Query Language), ma in realtà significa SQL Server (il sistema di database di Microsoft relatinonal) da essa, e se si sta utilizzando SQL Server 2005 o più recente, è possibile utilizzare un CTE (Common Table Expression) per questo scopo.

Con questo CTE, è possibile suddividere i dati in base a determinati criteri, ad esempio il proprio ItemId (o una combinazione di colonne) e disporre di SQL Server tutte le righe a partire da 1 per ciascuna di queste partizioni, ordinate da altri criteri - Probabilmente vale a dire version (o qualche altra colonna).

Quindi provare qualcosa di simile:

;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 

sostanza, si sta partizionamento dei dati da parte di alcuni criteri e la numerazione ogni partizione, a partire da 1 per ogni nuova partizione, ordinata da alcuni altri criteri (ad esempio, Data o Versione).

Quindi per ogni "partizione" di dati, la voce "più recente" ha RowNum = 1 e tutti gli altri che appartengono alla stessa partizione (per mezzo degli stessi valori di partitinio) avranno valori numerati in sequenza da 2 a a molte righe ci sono in quella partizione.

Se si desidera mantenere solo la voce più recente, eliminare qualsiasi cosa con un RowNum maggiore di 1 e il gioco è fatto!

4

In SQL Server 2005 e soprattutto:

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

Prova qualcosa di simile:

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

Naturalmente, che ci si vuole limitare la MAX (versione) per solo le versioni del campo sei volendo cancellare.

0

Probabilmente è necessario guardare this Stack Overflow answer (eliminare prima di righe duplicate).

In sostanza, la tecnica utilizza il raggruppamento (o facoltativamente, le finestre) per trovare il valore ID minimo di un gruppo per eliminarlo. Potrebbe essere più preciso cancellare le righe con il valore <> max (identificativo riga).

Quindi:

  1. goccia indice univoco
  2. Dati di carico
  3. cancellare i dati utilizzando il meccanismo di raggruppamento (idealmente in una transazione, in modo da poter rollback se c'è un errore), poi commettono
  4. Ricreare l'indice.

Nota che ricreare un indice su un grande tavolo può richiedere molto tempo.

+1

La soluzione di marc_s è un modo elegante per farlo. – rorycl

Problemi correlati