Une autre façon de procéder est la suivante
;
--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;
J'utilise ORDER BY (SELECT 0)
ci-dessus car le choix de la ligne à préserver en cas d'égalité est arbitraire.
Pour conserver le dernier en date dans RowID
par exemple, vous pourriez utiliser ORDER BY RowID DESC
Plans d'exécution
Le plan d'exécution est souvent plus simple et plus efficace que celui de la réponse acceptée, car il ne nécessite pas de jointure automatique.
![Execution Plans]()
Ce n'est cependant pas toujours le cas. Un endroit où le GROUP BY
peut être préférée dans les situations où une agrégat de hachage serait choisi de préférence à un agrégat de flux.
En ROW_NUMBER
donnera toujours à peu près le même plan, alors que la solution de la GROUP BY
est plus flexible.
![Execution Plans]()
Les facteurs qui pourraient favoriser l'approche de l'agrégat de hachage seraient les suivants
- Pas d'index utile sur les colonnes de partitionnement
- relativement moins de groupes avec relativement plus de doublons dans chaque groupe
Dans les versions extrêmes de ce deuxième cas (s'il y a très peu de groupes avec beaucoup de doublons dans chacun d'entre eux), on peut aussi envisager d'insérer simplement les lignes à conserver dans une nouvelle table, alors TRUNCATE
-sur l'original et les recopier pour minimiser la journalisation par rapport à la suppression d'une très grande partie des lignes.
14 votes
Un conseil rapide pour les utilisateurs de PostgreSQL qui lisent ceci (beaucoup, à en juger par la fréquence des liens) : Pg n'expose pas les termes CTE en tant que vues actualisables.
DELETE FROM
un terme CTE directement. Voir stackoverflow.com/q/18439054/3986700 votes
@CraigRinger la même chose est vraie pour Sybase - J'ai rassemblé les solutions restantes ici (elles devraient être valables pour PG et d'autres, aussi : stackoverflow.com/q/19544489/1855801 (il suffit de remplacer le
ROWID()
par la colonne RowID, le cas échéant)13 votes
Juste pour ajouter une mise en garde ici. Lorsque vous exécutez un processus de déduplication, vérifiez toujours d'abord ce que vous supprimez ! C'est l'un des domaines où il est très fréquent de supprimer accidentellement de bonnes données.