Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Come eliminare le righe duplicate in SQL Server 2008?

Il modo più semplice è con un CTE (espressione di tabella comune). Uso questo metodo quando ho dati grezzi da importare; la prima cosa che faccio per disinfettarlo è assicurarmi che non ci siano duplicati, che ho una sorta di handle univoco per ogni riga.

Riepilogo:

WITH numbered AS (
    SELECT ROW_NUMBER() OVER(PARTITION BY [dupe-column-list] ORDER BY [dupe-column-list]) AS _dupe_num FROM [table-name] WHERE 1=1
)
DELETE FROM numbered WHERE _dupe_num > 1;

La parte "dupe-column-list" è dove elenchi tutte le colonne coinvolte in cui desideri che i valori siano univoci. L'ORDINE PER è dove decidi, all'interno di una serie di duplicati, quale riga "vince" e quale viene eliminata. (Il "WHERE 1=1" è solo un'abitudine personale.)

Il motivo per cui funziona è perché Sql Server mantiene un riferimento univoco interno a ciascuna riga di origine selezionata nel CTE. Quindi, quando DELETE viene eseguito, conosce la riga esatta da eliminare, indipendentemente da ciò che hai inserito nell'elenco di selezione del tuo CTE. (Se sei nervoso, puoi cambiare "DELETE" in "SELECT *", ma dal momento che hai righe duplicate, non ti aiuterà; se potessi identificare in modo univoco ogni riga, non leggeresti questo .)

Esempio:

CREATE TABLE ##_dupes (col1 int, col2 int, col3 varchar(50));
INSERT INTO ##_dupes 
    VALUES (1, 1, 'one,one')
        , (2, 2, 'two,two')
        , (3, 3, 'three,three')
        , (1, 1, 'one,one')
        , (1, 2, 'one,two')
        , (3, 3, 'three,three')
        , (1, 1, 'one,one')
        , (1, 2, '1,2');

Delle 8 righe, ne hai 5 coinvolte con problemi duplicati; 3 righe devono essere rimosse. Puoi vedere i problemi con questo:

SELECT col1
    , col2
    , col3
    , COUNT(1) AS _total 
    FROM ##_dupes 
    WHERE 1=1 
    GROUP BY col1, col2, col3
    HAVING COUNT(1) > 1
    ORDER BY _total DESC;

Ora esegui la seguente query per rimuovere i duplicati, lasciando 1 riga da ogni set di duplicati.

WITH numbered AS (
    SELECT ROW_NUMBER() OVER(PARTITION BY col1, col2, col3 ORDER BY col1, col2, col3) AS _dupe_num FROM ##_dupes WHERE 1=1
)
DELETE FROM numbered WHERE _dupe_num > 1;

Ora ti rimangono 5 righe, nessuna delle quali è duplicata.