[Access SQL] le cas DISTINCTROW

Si vous avez déjà cherché des solutions pour éliminer les doublons dans vos tables/requêtes, vous connaissez probablement déjà le mot-clé DISTINCT qui fait partie de la norme SQL.

Mais connaissez-vous le prédicat Access DISTINCTROW ?

Certains, oui :
DISTINCTROW ou l’exemple parfait de l’absurdité d’Access !

Rideau… ;-)


Je développe un peu quand même en prenant un exemple pratique avec la requête suivante (qui change un peu du traditionnel schéma : Client-1—–∞-Commande):

On recherche les élèves qui ont exprimé au moins une fois le souhait de suivre le module n°7 dans leurs trois premiers vœux. Parmi ces élèves on ne retiendra que ceux qui n’ont jamais pu obtenir d’affectation sur ce module.

La requête retourne 59 lignes en tout :

Les doublons s’expliquent ici car lors des différentes rotations (NumRotation=1,2,…), certains élèves peuvent redemander ce module n°7 tant qu’ils n’ont pu l’obtenir (par manque de place car la demande est forte sur ce module !).

1ère tentative d’élimination des doublons :

Une bonne vielle clause DISTINCT :

Vous pouvez utiliser la propriété UniqueValues lorsque vous souhaitez écarter les enregistrements qui contiennent des données en double dans les champs affichés en mode Feuille de données. Par exemple, si le résultat d’une requête inclut plusieurs champs, la combinaison des valeurs de tous les champs doit être unique pour un enregistrement donné à inclure dans les résultats.

Au niveau SQL :
SELECT DISTINCT Eleve.idEleve, Eleve.NomEleve, Eleve.PrenomEleve FROM …

La requête ne retourne plus que 41 enregistrements sans doublon.

En clair, l’opérateur DISTINCT agit donc en omettant les doublons sur la combinaison des colonnes affichées (ici le triplet{idEleve,NomEleve,PrenomEleve} ).

2ème tentative d’élimination des doublons :

Vous pouvez utiliser la propriété UniqueRecords lorsque vous souhaitez omettre les données basées sur des enregistrements en double entiers, pas uniquement des champs en double. Microsoft Access considère qu’un enregistrement est unique pour autant que la valeur d’un champ dans l’enregistrement diffère de la valeur du même champ dans un autre enregistrement.

Au niveau SQL :
SELECT DISTINCTROW Eleve.idEleve, Eleve.NomEleve, Eleve.PrenomEleve FROM …

Notez que nous sommes dans le cadre d’utilisation normale de la clause DISTINCTROW :

DISTINCTROW n’a d’effet que si vous sélectionnez des champs pour certaines tables utilisées dans la requête, mais pas toutes. DISTINCTROW est ignorée si votre requête n’inclut qu’une seule table, ou si vous produisez des champs à partir de toutes les tables.

La requête omettant les données basées sur des enregistrements en double de la table Eleve (et pas seulement les doublons sur les seules colonnes affichées), celle-ci retournera …les mêmes lignes qu’avec la clause DISTINCT, rigoureusement…

Conclusion :

La différence entre DISTINCT et DISTINCTROW est donc subtile et a de quoi embrouiller le développeur qui dans ce cas particulier a déjà deux solutions pour obtenir le même résultat :
SELECT DISTINCT Eleve.idEleve, Eleve.NomEleve, Eleve.PrenomEleve FROM …
ou bien,
SELECT DISTINCTROW Eleve.idEleve, Eleve.NomEleve, Eleve.PrenomEleve FROM …

L’écart entre les durées moyennes d’exécution des deux requêtes avec DISTINCT et DISTINCTROW est négligeable sur mon jeu de données. Rien à attendre sur les performances en faveur de l’un ou l’autre a priori.

Le connaisseur pourra quand même rétorquer que le DISTINCTROW agissant au niveau de l’enregistrement, la requête devient « updatable » (eupedatabeul, miseàjourable) contrairement à celle avec DISTINCT.

Au fait, DISTINCTROW est spécifique à Access et ne fait pas partie de la norme SQL. Comment faire avec du SQL standard ?

On peut se contenter de DISTINCT ou bien on emploie l’opérateur EXISTS :

SELECT Eleve.idEleve, Eleve.NomEleve, Eleve.PrenomEleve  
FROM Eleve
WHERE EXISTS
(
  SELECT 0 FROM VoeuEleve LEFT JOIN AffectationEleve
  ON VoeuEleve.idEleve=AffectationEleve.idEleve
                   AND VoeuEleve.idModule=AffectationEleve.idModule
  WHERE VoeuEleve.idModule=7 AND VoeuEleve.OrdreVoeu<=3
                  AND AffectationEleve.idEleve IS NULL
                  AND VoeuEleve.idEleve=Eleve.idEleve
) ;

Certes, on sort des assistants pour rédiger cette requête…

…mais le temps d’exécution de la requête avec EXISTS me semble bien meilleur et les données peuvent aussi être mises à jour…

Si vous avez un retour d’expérience avec DISTINCTROW, n’hésitez pas à en faire profiter ici…

2 réflexions au sujet de « [Access SQL] le cas DISTINCTROW »

Laisser un commentaire