Outra maneira possível de fazer isso é
;
--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3
ORDER BY ( SELECT 0)) RN
FROM #MyTable)
DELETE FROM cte
WHERE RN > 1;
Estou usando ORDER BY (SELECT 0)
acima, pois é arbitrário qual linha preservar em caso de empate.
Para preservar o mais recente RowID
, por exemplo, você pode usarORDER BY RowID DESC
Planos de Execução
O plano de execução para isso geralmente é mais simples e mais eficiente do que o da resposta aceita, pois não requer a auto-junção.
Nem sempre é esse o caso. Um local em que a GROUP BY
solução pode ser preferida são as situações em que um agregado de hash seria escolhido em preferência a um agregado de fluxo.
A ROW_NUMBER
solução sempre dará praticamente o mesmo plano, enquanto a GROUP BY
estratégia é mais flexível.
Fatores que podem favorecer a abordagem agregada de hash seriam
- Nenhum índice útil nas colunas de particionamento
- relativamente poucos grupos com relativamente mais duplicatas em cada grupo
Nas versões extremas desse segundo caso (se houver muito poucos grupos com muitas duplicatas em cada um), também seria possível inserir simplesmente as linhas para manter em uma nova tabela e, em seguida, inserir TRUNCATE
o original e copiá-las para minimizar o registro em comparação com a exclusão de um proporção muito alta das linhas.
DELETE FROM
usá-lo diretamente. Veja stackoverflow.com/q/18439054/398670