Agrégation
Dernière mise à jour
Dernière mise à jour
L'idée d'agrégation est de pouvoir calculer des synthèses à partir des données récupérées d'une requête SQL.
Par exemple, je veux calculer la somme de valeurs extraites d'une requête, ou bien compter le nombre de lignes retournées.
Il y a plusieurs opérations d'agrégation possibles :
Compter : count
La somme : sum
La moyenne : avg
Le minimum : min
Le maximum : max
À noter, si j'utilise un opérateur d'agrégation, le résultat sortant ne contiendra que la valeur d'agrégation, et pas toutes les lignes demandées par la requête select
!
Par exemple, je veux connaître le nombre d'interventions et le budget moyen qui ont eu lieu dans l'Eure :
Le résultat est :
Intervention | Budget moyen |
---|---|
À noter, qu'un plan d'action implicite a été créé par notre SGBDR :
Une table temporaire contenant les lignes qui remplissent notre clause where
est construit
Cette table est traversée, en calculant les valeurs synthèses
count
et distinct
Je veux savoir le nombre total d'intervenants qui sont intervenus en novembre 2022.
Pour cela, il y a plusieurs jointures à faire :
on commence par récupérer tous les événements de cette période (la table action_event
)
pour chaque événement, on peut récupérer les intervenants, en faisant un produit cartésien avec event_animator
(avec la contrainte que le eventId
soit identique)
Je fais un premier teste de construction d'une requête SQL :
Résultat : 3397 lignes
ALERTE ! ALERTE ! ALERTE !
Ici il y a eu une mauvaise interprétation des données, ou bien de la question !
Je veux connaître le nombre d'intervenants, alors cette requête me donne le nombre d'interventions par chaque intervenant !
Vous ne voyez pas trop la différence ? Dans ce cas, je conseille toujours de visualiser les données avant de procéder avec l'agrégation.
Commençons juste par visualiser l'ID de l'intervenant et les dates :
Qui retourne :
Ah oui ! On voit toute suite que l'intervenant 5ff8c7cfbf559e0012e3123c
intervient dans plusieurs événements pendant la période. Et, il sera compté 5 fois dans notre agrégation !
On peut utiliser distinct
pour corriger l'erreur :
Le résultat : 772 intervenants
Attention aux détails :
On utilise l'opérateur distinct
uniquement sur l'attribut animatorId
, car distinct agit sur l'ensemble des attributs. Si on avait gardé startUtc
, distinct
n'aurait pas changé le résultat
Ensuite, on compte le nombre de résultats avec count
Je sais maintenant qu'il y a eu 772 intervenants qui ont travaillé le mois de novembre 2022. En revanche, maintenant, je veux construire un rapport qui détaille le nombre total d'événements de chaque intervenant.
Dans ce cas, il serait utile de grouper les résultats de la requête précédente, et compter le nombre de lignes par groupe. On utilise la clause group by
:
Le résultat :
Attention aux détails :
la clause group by
peut agir sur plusieurs attributs (comme distinct
), et va créer des groupes, des tuples identiques
j'enlève donc distinct
de la requête
Explorer un peu plus group by
!
Enlever la clause count(*)
de la requête (en laissant group by
). Vous remarquez des différences ?
Ajoutez startUtc
à la clause select
(uniquement). Vous arrivez à expliquer le résultat ?
Ensuite, ajoutez startUtc
à la clause group by
. Vous arrivez à expliquer le résultat ?
Bien sûr, notre résultat n'est pas très intéressant pour notre rapport. Idéalement, je récupérerai les noms/prénoms des intervenants pour mon rapport, qui demande d'autres jointures :
Je veux générer un rapport qui me sort les salaires à payer pour chaque intervenant pour le mois de novembre 2022. Le rapport doit lister :
Le prénom et nom de l'intervenant
Le nombre d'heures travaillé
Le total à lui payer
L'intervenant est payé par heure. Donc, pour un intervenant payé à 25 € l'heure, pour événement de 2 heures, l'intervenant sera payé 50 €.
Astuces et feuille de route :
Commencez par analyser le schéma :
Quel(s) attribut(s) décrive(nt) la durée d'un événement ?
On récupère où son tarif horaire ?
Essayez d’abord construire une requête qui indique le début et la fin de chaque événement de chaque intervenant, en affichant son tarif horaire
Ensuite, vous arrivez à transformer le début et la fin de chaque événement en nombre d'heures ? Astuce : regardez les fonctions timediff
et time_to_sec
Ensuite, vous arrivez à calculer la somme à payer pour chaque événement ?
Ensuite, essayez de calculer la synthèse (agrégation) pour chaque intervenant
having
Parfois, on aimerait appliquer un deuxième phase de filtrage sur le résultat d'une synthèse.
Par exemple, imaginons qu'il y a une règle qui interdit le travail de plus que 35 heures par mois. On aimerait sortir un rapport de tous les intervenants qui ont travaillé plus que 35 heures pour la période de novembre 2022.
On peut d'abord s'inspirer de l'exercice précédent pour sortir le nombre d'heures travaillées par chaque intervenant :
On peut ensuite appliquer un deuxième filtre sur ce résultat avec la clause having
:
null
et l'agrégationAttention ! Toutes les fonctions sauf count
ignorent les valeurs null
.
Les exercices suivants sont basés sur la base de données SAKILA, une base de données de test fourni par MySQL.
Affichez la liste des noms de famille des acteurs, et comptez le nombre d’acteurs qui partagent le même nom de famille. Appelez cette deuxième colonne « shared_surname »
Affichez uniquement la liste des acteurs qui partagent le même nom de famille.
Calculez le prix de location moyen pour chaque genre de film. Quel est le prix moyen pour le genre Drama
?
Combien de genres ont un prix moyen supérieur à 3€ ?
animatorId | startUtc |
---|---|
animatorId | Evénements |
---|---|
animatorId | givenName | familyName | hours |
---|---|---|---|
animatorId | givenName | familyName | hours |
---|---|---|---|
123
339.390244
5ff8c7cfbf559e0012e3123c
2022-11-18 09:00:00
5ff8c7cfbf559e0012e3123c
2022-11-25 09:00:00
5ff8b8489b4af50013c919cd
2022-11-10 10:00:00
5ff8b8489b4af50013c919cd
2022-11-17 10:00:00
5ff8b8489b4af50013c919cd
2022-11-24 10:00:00
60cb4a6500c00100129f6de2
2022-11-09 16:00:00
60cb4a6500c00100129f6de2
2022-11-16 16:00:00
60cb4a6500c00100129f6de2
2022-11-23 16:00:00
60cb4a6500c00100129f6de2
2022-11-30 16:00:00
5ff8c5bf4875ad00136fbeb7
2022-11-07 14:15:00
61fd46f0f3cd6f0019f27645
2022-11-08 14:00:00
61fd46f0f3cd6f0019f27645
2022-11-15 14:00:00
5ff8b88c4875ad00136fbce3
2022-11-22 14:00:00
61fd46f0f3cd6f0019f27645
2022-11-29 14:00:00
...
...
5f1fd5776ecbce00107beb84
4
5f3a82f408d0f10010d8eafe
4
5f3b9e0f6ecbce00107bec30
26
5f3d14af08d0f10010d8eb2a
19
5f3d154f6ecbce00107bec8d
15
...
...
5f1fd5776ecbce00107beb84
Antoinette
Mercier
4.00
5f3a82f408d0f10010d8eafe
Amarande
Paul
4.00
5f3b9e0f6ecbce00107bec30
Landry
Fernandez
71.00
5f3d14af08d0f10010d8eb2a
Alcime
Dubois
36.00
5f3d154f6ecbce00107bec8d
Herluin
Royer
51.00
5f3b9e0f6ecbce00107bec30
Landry
Fernandez
71.00
5f3d14af08d0f10010d8eb2a
Alcime
Dubois
36.00
5f3d154f6ecbce00107bec8d
Herluin
Royer
51.00
..
..
..
..