L'extraction d'enregistrements uniques en SQL est devenue une tâche cruciale avec le passage massif des organisations à la conservation de données multidimensionnelles. Parfois, il est nécessaire d'afficher des lignes non répétées par combinaison de plusieurs colonnes, parfois — uniquement par une clé unique.
Historique de la question :
Les premières versions de SQL proposaient uniquement DISTINCT pour filtrer les doublons. Ensuite, des techniques structurelles sont apparues, dont GROUP BY pour l'agrégation par ensembles de valeurs uniques et des fonctions de fenêtre comme ROW_NUMBER() pour des scénarios plus flexibles de gestion des doublons, par exemple : sélection par "dernier" ou "premier" enregistrement.
Problème :
DISTINCT fonctionne uniquement au niveau des champs dans SELECT, tandis que GROUP BY nécessite des agrégations. Les fonctions de fenêtre permettent une logique avancée, mais leur utilisation entraîne souvent des erreurs si l'ordre de sélection des lignes n'est pas soigneusement pensé. Les développeurs confondent souvent ces approches, les erreurs entraînant des résultats incorrects.
Solution :
Exemple de code :
Obtenir un dernier enregistrement sur les commandes pour chaque client :
WITH OrdersRank AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) as rn FROM Orders ) SELECT * FROM OrdersRank WHERE rn = 1;
Caractéristiques clés :
Peut-on utiliser DISTINCT avec des fonctions d'agrégation sans GROUP BY ?
Non, les fonctions d'agrégation nécessitent un groupement, sinon il y aura une erreur de syntaxe.
SELECT COUNT(DISTINCT CustomerID) -- correct SELECT SUM(Amount), DISTINCT CustomerID -- erreur !
Que se passe-t-il si dans GROUP BY tous les champs non agrégés de SELECT ne sont pas indiqués ?
Cela provoquera une erreur dans la plupart des SGBD : tous les champs dans SELECT, à l'exception des agrégats, doivent être répertoriés dans GROUP BY.
Peut-on "supprimer" les doublons à l'aide de fonctions de fenêtre sans sous-requête ?
Non : l'utilisation de ROW_NUMBER() à l'intérieur d'un seul SELECT ne filtre pas automatiquement les "répétitions", une requête externe est nécessaire pour sélectionner les lignes souhaitées.
A choisi DISTINCT sur toutes les colonnes pour une table de 20 millions de lignes : la requête a tourné des heures, résultat — timeout ou baisse de performance de la base de données.
Avantages :
Inconvénients :
Utilisation de fonctions de fenêtre : a obtenu uniquement le dernier enregistrement nécessaire pour le client en millisecondes; les précédents et répétés n'ont pas été chargés.
Avantages :
Inconvénients :