SQL DISTINCT et TOP dans la même requête

Cet article est inspiré d’une série de questions qu’une de mes lectrices, Nan, m’a récemment envoyées concernant DISTINCT, TOP et ORDER BY.

Tous les exemples de cette leçon sont basés sur Microsoft SQL Server Management Studio et la base de données AdventureWorks2012. Vous pouvez commencer à utiliser ces outils gratuits à l’aide de mon guide Getting Started Using SQL Server.

Comment les modificateurs SQL Top et Distinct SELECT fonctionnent-ils ensemble pour produire des résultats ?

Voici la question que Nan m’a envoyée à l’origine :

Je suis un peu confuse au sujet de SELECT DISTINCT et SELECT. Par exemple,

SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName

Est-ce que cela recherche des prénoms distincts ? Des prénoms et des noms combinés distincts ? Comment distinguer les colonnes utilisées pour l’évaluation distincte et les colonnes que nous voulons juste montrer dans la sortie ?

Qu’en est-il

Select Distinct TOP 10 LastName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY LastName

J’ai pensé que tout le monde aimerait connaître la réponse, alors je crée un billet de blog.

DISTINCT et TOP – Lequel arrive en premier ?

Regardons la première déclaration dont le but est de retourner une liste unique de noms et de prénoms.

SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName;

TOP 10 retournera les dix premiers éléments de l’ensemble ordonné, et DISTINCT supprimera tous les doublons. La question est de savoir ce qui se passe en premier ?

  • Est-ce que la table est triée par LastName et les dix premiers éléments pris, puis le nom en double est supprimé ?
  • Ou est-ce que les doublons sont supprimés, puis les éléments sont triés et les dix premiers éléments affichés ?

Avant de répondre à cette question, gardez à l’esprit que DISTINCT opère sur toutes les colonnes et expressions dans la clause SELECT. Ainsi, dans ce cas, l’instruction renverra des lignes distinctes pour FirstName et LastName.

Malheureusement, il n’existe pas de moyen direct d’utiliser DISTINCT sur un ensemble de champs et d’afficher les autres. Dès que vous ajoutez des colonnes à l’instruction SELECT, elles deviennent sous l’influence de l’opérateur DISTINCT. Je dis bien direct, car vous pourriez obtenir une liste distincte, puis utiliser un INNER JOIN pour ajouter d’autres colonnes. Il y a cependant des dangers à faire cela, car la jointure peut réintroduire des doublons.

Ajouter une clause TOP à DISTINCT est intéressant. Je n’étais pas sûr de ce qui se passerait, mais j’ai fait quelques expériences avec la base de données AdventureWorks et j’ai constaté que l’ordre de traitement se déroule à peu près comme suit :

  1. Sélectionner les valeurs DISTINCT de la table et les ordonner
  2. Sélectionner les x lignes supérieures des résultats de l’étape 1 et les afficher.

Si vous voulez essayer vous-même, commencez par

SELECT FirstName,
LastName
FROM Person.Person
ORDER BY LastName

Et remarquez les résultats. Suivez la trace de « Kim Ambercombie ». Remarquez comment il y a trois entrées pour son nom.

Résultats triés par Nom de famille

Maintenant lancez

SELECT DISTINCT FirstName,
LastName
FROM Person.Person
ORDER BY LastName

Et vous verrez que « Kim Ambercombine » n’apparaît qu’une seule fois.

Liste unique ordonnée par LastName

Alors exécutez

SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName

Et vous verrez qu’il retourne les 10 premiers noms et prénoms uniques triés par LastName.

Premières 10 lignes uniques ordonnées par LastName

Si vous vous demandez ce qui se passe en premier, les opérations DISTINCT ou TOP 10, alors comparez les résultats des deux dernières requêtes.

Notez que la requête « DISTINCT TOP 10 » inclut les 10 premières lignes de la requête de la requête « DISTINCT ».

De ce fait, nous savons qu’une liste DISTINCT est d’abord créée, puis que les 10 premiers éléments sont renvoyés.

Plan de requête montrant l’ordre d’exécution

Vous pouvez également confirmer cela en montrant le plan de requête. Pour ce faire, sélectionnez Requête -> Inclure le plan de requête réel dans le menu avant d’exécuter la requête.

L’icône « Stream Aggregate » correspond à l’opération DISTINCT et « Top » à celle TOP 10.

Il peut sembler quelque peu contre-intuitif de voir DISTINCT listé en premier dans l’instruction SELECT. Gardez simplement à l’esprit que le SQL n’est pas nécessairement traité dans l’ordre où un humain le lirait de gauche à droite.

DISTINCT et TOP avec les expressions de la liste SELECT

La deuxième partie de la question de Nan concernait la façon dont les expressions sont traitées avec l’opérateur DISTINCT.

Les expressions sont traitées de la même façon que la colonne en ce qui concerne DISTINCT et TOP. Commençons par une instruction select pour obtenir le prénom ainsi que le complet, que nous créons en ajoutant LastName à FirstName.

En outre, gardez à l’esprit, lorsque vous utilisez ORDER BY, que les éléments ORDER BY doivent apparaître dans la liste select lors de l’utilisation de Distinct. Compte tenu de cela, je dois modifier l’instruction présentée dans la question initiale :

SELECT DISTINCT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY LastName

Ne s’exécutera pas puisque LastName ne figure pas dans la liste SELECT. Oui, il fait partie d’une expression dans la liste select, mais il n’est pas là tout seul. Il est valide d’ordonner par FullName.

Nous utiliserons cet ordonnancement dans les exemples ci-dessous.

L’instruction

SELECT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName

Retourne 19972 lignes. Lorsque nous ajoutons Distinct

SELECT DISTINCT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName

Alors 19516 lignes sont retournées. Enfin en ajoutant Top 10, on retourne les 10 premières combinaisons de noms distincts.

SELECT DISTINCT TOP 10 FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName

Essayez d’exécuter ces requêtes sur la base de données AdventureWork et vous verrez par vous-même que le comportement est le même que celui que nous trouvons en travaillant exclusivement avec des colonnes.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.