Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como excluir linhas duplicadas no SQL Server 2008?


A maneira mais simples é com um CTE (expressão de tabela comum). Eu uso esse método quando tenho dados brutos para importar; a primeira coisa que faço para sanitizá-lo é garantir que não haja duplicatas --- que tenho algum tipo de identificador exclusivo para cada linha.

Resumo:
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;

A parte "dupe-column-list" é onde você lista todas as colunas envolvidas onde você deseja que os valores sejam únicos. O ORDER BY é onde você decide, dentro de um conjunto de duplicatas, qual linha "ganha" e qual é excluída. (O "WHERE 1=1" é apenas um hábito pessoal.)

A razão pela qual funciona é porque o Sql Server mantém uma referência interna exclusiva para cada linha de origem selecionada no CTE. Portanto, quando o DELETE é executado, ele sabe a linha exata a ser excluída, independentemente do que você colocar na lista de seleção do seu CTE. (Se você está nervoso, você pode alterar o "DELETE" para "SELECT *", mas como você tem linhas duplicadas, não vai ajudar; se você pudesse identificar exclusivamente cada linha, você não estaria lendo isso .)

Exemplo:
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');

Das 8 linhas, você tem 5 envolvidas com problemas duplicados; 3 linhas precisam ser removidas. Você pode ver os problemas com isso:
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;

Agora execute a seguinte consulta para remover as duplicatas, deixando 1 linha de cada conjunto de duplicatas.
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;

Agora você tem 5 linhas, nenhuma das quais está duplicada.