Regroupement avec GROUP BY

La clause SQL  « GROUP BY » permet de regrouper les tuples d’une requête selon la valeur de champs identiques.

Soit les tables utilisées pour les exemples :

Create table Course (IDcourse number, Ville varchar2(250 char), distance number) ;

Create table Coureur (IDcoureur number, nom varchar2(250 char),  prenom varchar2(250 char),  date_naissance date) ;

Create table Score (IDcourse number, IDcoureur number, categorie varchar2(250 char), temps interval day(1) to second (5)) ;



Group by s’apparente au mot clé distinct dans le select :

Select distinct ville, distance from course ;

Et équivalent à

Select ville, distance from course group by ville, distance;


Cependant GROUP BY permet d’effectuer des opérations sur les regroupements :

-- Records pour chaque categorie de course (parmi tous les participants, toutes les courses)

Select categorie, min(temps)  from Score group by categorie where IDcourse = 3


Ces opérations d’agrégation portent généralement sur des nombres (ou associés) :

Count = nombre dans le regroupement ; Avg = moyenne ; sum = somme ; min = la plus petite valeur ; max = la plus grande valeur ; …


Voici un autre exemple :

-- Les records personnels de Jean Dupond sur chaque distance.
Select distance, min(temps) from Score s
inner join Coureur c on s.IDcoureur = c.IDcoureur
inner join Course ce on ce.IDcourse = Score.IDcourse
Group by distance
Where c.nom  = ‘Dupond’ and prenom = ‘Jean’

-- La ville de chacun de ces records
Select ville, distance, temps from Course cem
                Inner join Score sm on sm.IDcourse = cem.IDcourse)
Where temps =
(Select min(temps) from Score s
inner join Coureur c on s.IDcoureur = c.IDcoureur
inner join Course ce on ce.IDcourse = Score.IDcourse
Group by distance
Where c.nom  = ‘Dupond’ and prenom = ‘Jean’
)



Pourquoi doit-on obligatoirement passer par cette sous-requête, ne peut-on pas simplement ajouter le champ ville dans la requête précédente ?

Non, ce n’est pas possible, Oracle impose que tous les champs d’un select soit dans la clause group by, hormis les champs calculés, au risque de retourner une erreur ORA-00979.

En effet, dans votre logique, chaque temps est unique, or techniquement, il est possible d’avoir deux temps égaux dans deux villes différentes.

Une requête ne peut fournir un résultat arbitraire (MySQL, plus permissif l’autorise par défaut – réglage de ONLY_FULL_GROUP_BY - mais mathématiquement il y a un problème) car le SGBD pourrait « choisir » la ville parmi les meilleurs temps.

Le résultat de la requête ci-dessus fournirait, quant à lui, 2 lignes correspondant au même temps.


WM_CONCAT


Le classement d’une course de manière simple est donné par la requête suivante :

select rownum, concat(upper(nom), prenom), temps
from score inner join coureur on coureur.IDcoureur = score.IDcoureur
order by temps asc



Or en cas d’égalité, nous désirons avoir les coureurs à égalité dans la même ‘ligne’ du tableau résultant.
Nous allons alors utiliser l’opérateur WM_CONCAT permettant de concaténer une chaîne de caractères au travers de la clause group by :


select wm_concat(concat(upper(nom), prenom)), temps
from score inner join coureur on coureur.IDcoureur = score.IDcoureur
group by temps
order by temps asc




Vous n'avez pas trouver réponse à votre question ? Préciser votre recherche :

Catégories