DISTINCT pour supprimer les doublons en SQL
Par défaut, un SELECT renvoie toutes les lignes qui correspondent, doublons compris. Avec DISTINCT, vous demandez à SQLite de fusionner les lignes identiques sur les colonnes sélectionnées : chaque combinaison unique n'apparaît alors qu'une seule fois.
Cinq lignes en entrée, trois en sortie. SQLite a regardé la colonne customer, viré les doublons, et renvoyé une ligne par valeur unique. Attention : l'ordre n'est pas garanti — ajoutez un ORDER BY si ça compte pour vous.
DISTINCT s'applique à toute la liste du SELECT
C'est là que beaucoup se font avoir. DISTINCT ne choisit pas une colonne en particulier à dédupliquer ; il déduplique les lignes entières en se basant sur l'ensemble des colonnes sélectionnées.
Chaque combinaison unique (customer, country) n'apparaît qu'une seule fois. Si le même client figure avec deux pays différents, vous verrez les deux lignes — pour SQLite, ce ne sont pas des doublons.
Il n'existe pas de syntaxe DISTINCT(customer) qui ignorerait les autres colonnes. Les parenthèses peuvent prêter à confusion, mais SELECT DISTINCT(customer), country est interprété exactement comme SELECT DISTINCT customer, country — les parenthèses ne servent qu'à regrouper une expression. Si vous voulez vraiment une seule ligne par client avec un pays choisi, il faudra passer par GROUP BY combiné à une fonction d'agrégation.
COUNT DISTINCT en SQLite
Un besoin classique : combien de valeurs uniques contient une colonne ? COUNT(*) compte les lignes, COUNT(col) compte les valeurs non-NULL, et COUNT(DISTINCT col) compte les valeurs uniques non-NULL.
Cinq commandes, trois clients uniques, trois pays uniques. COUNT(DISTINCT ...) est la forme agrégée la plus utile de DISTINCT — on y a recours dès qu'on veut savoir « combien d'éléments différents apparaissent ».
Attention : SQLite n'autorise qu'une seule colonne à l'intérieur de COUNT(DISTINCT ...). Pour compter des combinaisons uniques sur plusieurs colonnes, il faut passer par une sous-requête : SELECT COUNT(*) FROM (SELECT DISTINCT a, b FROM t).
Comportement de DISTINCT face à NULL
NULL traîne une réputation un peu bizarre en SQL, puisque NULL = NULL renvoie NULL et non TRUE. Mais DISTINCT fait une exception bienvenue : pour la déduplication, tous les NULL sont considérés comme égaux entre eux.
Trois lignes ressortent : 'ada@example.com', 'dan@example.com', et un seul NULL. Les trois adresses NULL ont été regroupées en une seule. La même règle s'applique à GROUP BY ainsi qu'aux opérations ensemblistes comme UNION — bon à garder en tête quand on cherche à comprendre « pourquoi cette ligne NULL n'apparaît qu'une fois au lieu de trois ? »
DISTINCT s'exécute avant ORDER BY et LIMIT
Les clauses d'un SELECT suivent un ordre logique : FROM → WHERE → GROUP BY → HAVING → SELECT/DISTINCT → ORDER BY → LIMIT. Autrement dit, DISTINCT élimine d'abord les doublons, puis ORDER BY trie ce qu'il reste, et enfin LIMIT réduit le résultat.
WHERE ne garde que quatre lignes, DISTINCT fusionne les doublons de Boris, ORDER BY trie par ordre alphabétique et LIMIT ne renvoie que les deux premières. Ça vaut le coup de dérouler l'exemple une fois mentalement — la plupart des confusions sur l'ordre des résultats viennent du fait qu'on oublie à quel moment chaque étape intervient.
DISTINCT vs GROUP BY en SQLite
Quand il s'agit simplement de supprimer les doublons, ces deux requêtes renvoient exactement les mêmes lignes :
Même résultat. La vraie différence se voit dans ce que vous pouvez faire ensuite :
DISTINCTsert uniquement à dire « donne-moi des lignes uniques ».GROUP BYsert à « regrouper les lignes et calculer quelque chose par groupe » —COUNT(*),SUM(amount),MAX(created_at), etc.
Si vous vous retrouves à utiliser DISTINCT et que vous réalisez ensuite qu'il te faut aussi un total par client, c'est le signal qu'il faut passer à GROUP BY :
Une ligne par client, avec les agrégats que vous vouliez. DISTINCT ne saurait pas faire ça — il n'a aucun moyen d'exprimer « une ligne par groupe plus une somme ».
Quelques pièges à garder en tête
- Les performances.
DISTINCToblige généralement SQLite à trier ou hacher les lignes pour repérer les doublons. Sur de gros volumes, un index sur la ou les colonnes dédupliquées aide beaucoup. Si vous faitesSELECT DISTINCTsur toutes les colonnes d'une table large, demandez-vous si vous avez réellement besoin de toutes ces colonnes. DISTINCT *est rare. C'est syntaxiquement correct —SELECT DISTINCT * FROM tdéduplique les lignes entières — mais si votre table a une clé primaire, chaque ligne est déjà unique, donc ça ne sert à rien.- À ne pas confondre avec
UNIQUE.UNIQUEest une contrainte posée sur une table qui empêche carrément l'insertion de doublons.DISTINCT, lui, est un filtre appliqué au moment de la requête qui masque les doublons dans le résultat. Deux outils, deux usages.
La suite : les expressions CASE
Une fois que vous savez modeler vos lignes de résultat avec SELECT, WHERE, ORDER BY et DISTINCT, l'étape suivante, c'est la logique conditionnelle à l'intérieur d'une requête. Les expressions CASE permettent de renvoyer des valeurs différentes selon des conditions — l'équivalent SQL d'une chaîne if/else, et c'est justement le sujet de la page suivante.
Questions fréquentes
Comment fonctionne SELECT DISTINCT en SQLite ?
SELECT DISTINCT supprime les lignes en double du résultat. SQLite compare l'ensemble des colonnes listées dans le SELECT et ne conserve qu'une ligne par combinaison unique. Le filtre s'applique après les WHERE et JOIN, mais avant ORDER BY et LIMIT.
Peut-on utiliser DISTINCT sur plusieurs colonnes en SQLite ?
Oui — et en réalité, DISTINCT porte toujours sur la totalité des colonnes du SELECT, jamais sur une seule. Par exemple, SELECT DISTINCT city, country FROM users renvoie chaque couple (city, country) unique. Il n'existe pas de syntaxe DISTINCT(city) qui ignorerait les autres colonnes : si c'est ce que vous cherchez, passez par un GROUP BY avec une fonction d'agrégation.
Comment DISTINCT gère-t-il les valeurs NULL en SQLite ?
Pour la déduplication, DISTINCT considère deux NULL comme égaux — donc plusieurs lignes contenant NULL sont fusionnées en une seule. C'est différent du comportement de = dans une clause WHERE, où NULL = NULL reste indéterminé. C'est une règle spéciale qui ne s'applique qu'à DISTINCT, GROUP BY et UNION.
Quelle différence entre DISTINCT et GROUP BY en SQLite ?
Pour de la simple déduplication, SELECT DISTINCT col et SELECT col FROM t GROUP BY col donnent exactement le même résultat. La différence est une question d'intention : DISTINCT quand on veut juste des lignes uniques, GROUP BY quand on veut en plus calculer des agrégats comme COUNT(*) ou SUM(amount) par groupe.