Otra posible forma de hacerlo es
;
--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;
Estoy usando lo ORDER BY (SELECT 0)
anterior, ya que es arbitrario qué fila conservar en caso de empate.
Para conservar el último en RowID
orden, por ejemplo, podría usarORDER BY RowID DESC
Planes de ejecucion
El plan de ejecución para esto es a menudo más simple y más eficiente que el de la respuesta aceptada, ya que no requiere la autounión.
Esto no es siempre el caso, sin embargo. Un lugar donde se GROUP BY
podría preferir la solución son las situaciones en las que se elegiría un agregado de hash en lugar de un agregado de flujo.
La ROW_NUMBER
solución siempre dará el mismo plan, mientras que la GROUP BY
estrategia es más flexible.
Los factores que podrían favorecer el enfoque agregado de hash serían
- No hay índice útil en las columnas de partición
- relativamente menos grupos con relativamente más duplicados en cada grupo
En las versiones extremas de este segundo caso (si hay muy pocos grupos con muchos duplicados en cada uno), también se podría considerar simplemente insertar las filas para mantenerlas en una nueva tabla, luego TRUNCATE
copiar el original y copiarlo de nuevo para minimizar el registro en comparación con eliminar un Muy alta proporción de las filas.
DELETE FROM
un término CTE directamente. Ver stackoverflow.com/q/18439054/398670