Cours 4 : Agrégats et GROUP BY
Agrégat Fonction qui effectue un calcul sur l ensemble des valeurs d un attribut pour un groupe de lignes Utilisation dans une clause SELECT ou dans une clause HAVING 3 types d agrégats : MIN, MAX SUM, AVG, VARIANCE, STDDEV COUNT 2013-2014 Bases de données 2
Agrégat sur un seul group Un seul groupe constitué de l ensemble des lignes sélectionnées par une éventuelle clause WHERE Syntaxe : SELECT aggregat 1 ([DISTINCT] expression 1 ),... aggregat n ([DISTINCT] expression n ) FROM noms-tables [WHERE conditions] 2013-2014 Bases de données 3
Exemple SELECT MIN(prix) AS prixmin, MAX(prix) AS prixmax FROM Tarif 2013-2014 Bases de données 4
Exemple (2) SELECT MIN(nomVille), MAX(nomville) FROM Ville 2013-2014 Bases de données 5
Exemple (3) SELECT MIN(dateDeb), MAX(dateDeb) FROM Tarif WHERE numvoyage = 4 2013-2014 Bases de données 6
Exemple (4) SELECT AVG(prix) FROM Tarif WHERE numvoyage = 4 SELECT AVG(DISTINCT prix), FROM Tarif WHERE numvoyage = 4 2013-2014 Bases de données 7
Exemple (5) numvoyage nomvoyage nbmin nbmax typepension 1 Circuit Heleni 15 P 4 Rhapsodie hongroise 15 40 P 5 Budapest, Vienne et Prague 20 DP 6 Arménie et Géorgie 15 30 P VOYAGE SELECT COUNT(*)FROM Voyage 4 2013-2014 Bases de données 8
Exemple (6) numvoyage nomvoyage nbmin nbmax typepension 1 Circuit Heleni 15 P 4 Rhapsodie hongroise 15 40 P 5 Budapest, Vienne et Prague 20 DP 6 Arménie et Géorgie 15 30 P VOYAGE SELECT COUNT(nbMax)FROM Voyage 2 2013-2014 Bases de données 9
Exemple (7) numvoyage nomvoyage nbmin nbmax typepension 1 Circuit Heleni 15 P 4 Rhapsodie hongroise 15 40 P 5 Budapest, Vienne et Prague 20 DP 6 Arménie et Géorgie 15 30 P VOYAGE SELECT COUNT(DISTINCT typepension) FROM Voyage 2 2013-2014 Bases de données 10
Agrégats sur un seul groupe (suite) Les valeurs NULL sont ignorées par les agrégats Un agrégat ne peut apparaître dans une clause WHERE (sauf dans un sousselect) Il est impossible de demander en résultat à la fois un attribut et un agrégat 2013-2014 Bases de données 11
Exemple SELECT COUNT(*), numvoyage FROM Voyage FAUX ERROR at line 1 : ORA-000937 : not a singlegroup group function 2013-2014 Bases de données 12
Groupements Pour subdiviser les lignes résultats d un ordre SELECT en plusieurs groupes il faut utiliser une clause GROUP BY Un groupe est formé d un ensemble de lignes ayant une ou plusieurs caractéristiques communes Il y a autant de groupes que de valeurs distinctes des caractéristiques décrites pour la formation des groupes 2013-2014 Bases de données 13
Groupements (suite) Un ordre SELECT avec une clause GROUP BY donne une ligne résultat pour chaque groupe Syntaxe : SELECT * [DISTINCT] liste-attributs FROM noms-tables [WHERE conditions] [GROUP BY liste-expressions] [HAVING conditions] [ORDER BY liste-critères] 2013-2014 Bases de données 14
Donner, pour chaque voyage, sa durée totale ainsi que son nombre d étapes Questions numvoyage numville numordre duree 1 1 1 3 1 5 2 1 4 7 1 3 4 7 4 1 4 8 2 2 4 9 3 1 5 7 2 3 ETAPE 5 10 1 3 5 11 3 1 5 12 4 4 5 13 5 1 6 14 1 5 6 14 5 1 6 15 2 2 6 16 3 2 6 17 4 1
Donner, pour chaque voyage, sa durée totale ainsi que son nombre d étapes Questions (2) numvoyage durée totale nb étapes 1 4 2 4 7 4 RESULTAT DE LA REQUETE 5 12 5 6 11 5 2013-2014 Bases de données 16
Questions (3) Donner, pour chaque voyage, sa durée totale ainsi que son nombre d étapes SELECT numvoyage, SUM(duree) AS "durée totale", COUNT(*) AS "nb étapes" FROM Etape GROUP BY numvoyage 2013-2014 Bases de données 17
Questions (4)... pour les voyages de numéro supérieur à 5 et ayant plus de 3 étapes SELECT numvoyage, SUM(duree) AS "durée totale", COUNT(*) AS "nb étapes" FROM Etape WHERE numvoyage > 5 GROUP BY numvoyage HAVING COUNT(*) > 3 2013-2014 Bases de données 18
Très important Dans la liste des attributs d un ordre SELECT avec une clause GROUP BY ne peuvent figurer que des caractéristiques de groupe, c est-à-dire : Soit des agrégats Soit des expressions figurant dans la clause GROUP BY 2013-2014 Bases de données 19
Exemple SELECT numvoyage, MIN(dateDeb), prix FROM Tarif GROUP BY numvoyage FAUX 2013-2014 Bases de données 20
Exemple (2) SELECT numvoyage, MIN(dateDeb) FROM Tarif GROUP BY numvoyage JUSTE 2013-2014 Bases de données 21
Exemple (3) SELECT numvoyage, MIN(dateDeb), prix FROM Tarif GROUP BY numvoyage, prix JUSTE 2013-2014 Bases de données 22
HAVING De même qu il est possible de sélectionner certaines lignes avec une clause WHERE, il est possible de sélectionner certains groupes de lignes en utilisant une clause HAVING Les conditions figurant dans la clause HAVING suivent les mêmes règles de syntaxe que celles d une clause WHERE 2013-2014 Bases de données 23
HAVING (suite) Les conditions figurant dans la clause HAVING ne peuvent porter que sur les caractéristiques du groupe : agrégats ou expression contenues dans la clause GROUP BY Une clause HAVING peut comporter un sous-select 2013-2014 Bases de données 24
Exemple SELECT numvoyage, AVG(prix) FROM Tarif WHERE datedeb >= '01-01-14' GROUP BY numvoyage HAVING AVG(prix) >= (SELECT AVG(prix) FROM Tarif WHERE datedeb >= '01-01-14') 2013-2014 Bases de données 25
Plan d exécution Si un SELECT comporte à la fois une clause WHERE et une clause GROUP BY : la clause WHERE sera d abord utilisée pour sélectionner les lignes les groupes seront constitués à partir des lignes sélectionnées les groupes seront alors eux-mêmes sélectionnés par la clause HAVING 2013-2014 Bases de données 26
Niveaux d agrégats Il est possible d appliquer au résultat d un SELECT avec GROUP BY un second niveau de fonction de groupe 2013-2014 Bases de données 27
Exemple SELECT MAX(COUNT(*)) FROM Voyage GROUP BY typepension numvoyage nomvoyage nbmin nbmax typepension 1 Circuit Heleni 15 P 4 Rhapsodie hongroise 15 40 P 5 Budapest, Vienne et Prague 20 DP 6 Arménie et Géorgie 15 30 P VOYAGE 2013-2014 Bases de données 28
Exemple (2) SELECT COUNT(*) FROM Voyage GROUP BY typepension COUNT(*) 3 1 RESULTAT DE LA REQUETE On demande le maximum ensuite 2013-2014 Bases de données 29
Questions Nombre de départs pour chacun des voyages dont le nom commence par C ou par R? SELECT V.numVoyage, COUNT(*) FROM Voyage V, Tarif T WHERE V.numVoyage = T.numVoyage AND (nomvoyage LIKE 'C%' OR nomvoyage LIKE 'R%') GROUP BY V.numVoyage 2013-2014 Bases de données 30
Questions (2) Nombre de départs pour chacun des voyages dont le nom commence par C ou par R? numvoyage nomvoyage nbmin nbmax typepension 1 Circuit Heleni 15 P 4 Rhapsodie hongroise 15 40 P 5 Budapest, Vienne et Prague 20 DP 6 Arménie et Géorgie 15 30 P VOYAGE 2013-2014 Bases de données 31
Questions (3) Nombre de départs pour chacun des voyages dont le nom commence par C ou par R? numvoyage datedeb prix 1 25-09-14 690 1 02-09-14 680 1 09-09-14 680 4 16-09-14 790 5 09-09-14 1400 TARIF 2013-2014 Bases de données 32
Questions (4) Nombre de départs pour chacun des voyages dont le nom commence par C ou par R? numvoyage nomvoyage nbmin nbmax typepension datedeb prix 1 Circuit Heleni 15 P 25-09-14 690 1 Circuit Heleni 15 P 02-09-14 680 1 Circuit Heleni 15 P 09-09-14 680 4 Rhapsodie hongroise 15 40 P 16-09-14 790 5 Budapest, Vienne 20 DP 09-09-14 1400 et Prague VOYAGE TARIF 2013-2014 Bases de données 33
Questions (5) Nombre de départs pour chacun des voyages dont le nom commence par C ou par R? numvoyage COUNT(*) 1 3 4 1 RESULTAT DE LA REQUETE 2013-2014 Bases de données 34
Questions (6) Numéros des voyages coûtant toujours le même prix (quelque soit la date de départ)? SELECT numvoyage FROM Tarif GROUP BY numvoyage HAVING MAX(prix) = MIN(prix) Variante HAVING COUNT(DISTINCT prix) = 1 2013-2014 Bases de données 35
Questions (7) Numéros des voyages coûtant toujours moins de 500? SELECT numvoyage FROM Tarif GROUP BY numvoyage HAVING MAX(prix) < 500 2013-2014 Bases de données 36
Questions (8) Numéros des voyages qui font étape pendant plus de 4 jours dans une même ville (par forcément de façon consécutives)? SELECT DISTINCT numvoyage FROM Etape GROUP BY numvoyage, numville HAVING SUM(duree) > 4 2013-2014 Bases de données 37
Questions (8 ) Numéros des voyages qui font étape pendant plus de 4 jours dans une même ville (par forcément de façon consécutives)? SELECT numvoyage, numville FROM Etape GROUP BY numvoyage, numville HAVING SUM(duree) > 4 2013-2014 Bases de données 38
Questions (9) Donner, pour chaque date de départ, les numéros des voyages qui partent à cette date SELECT datedeb, numvoyage FROM Tarif ORDER BY datedeb Utiliser GROUP BY et ORDER BY à bon escient 2013-2014 Bases de données 39
Questions (10) Donner, pour chaque date de départ, le nombre de voyages qui partent à cette date SELECT datedeb, COUNT(*) FROM Tarif GROUP BY datedeb 2013-2014 Bases de données 40
Erreurs classiques Utiliser dans la clause SELECT un attribut qui n est pas dans la clause GROUP BY Utiliser dans la clause HAVING un attribut qui n est pas dans la clause GROUP BY HAVING COUNT(*) = 0 et HAVING COUNT(*) >= 1 n ont pas de sens 2013-2014 Bases de données 41
Analyse des requêtes SELECT DISTINCT numvoyage, AVG(prix) FROM Tarif GROUP BY numvoyage Ici le DISTINCT est inutile 2013-2014 Bases de données 42
Analyse des requêtes (2) SELECT numvoyage, MIN(nomVoyage) FROM Voyage GROUP BY numvoyage Ici MIN et GROUP BY sont inutiles 2013-2014 Bases de données 43
Analyse des requêtes (3) SELECT DISTINCT typepension FROM Voyage GROUP BY typepension Ici GROUP BY est inutile et donc DISTINCT devient nécessaire 2013-2014 Bases de données 44
Analyse des requêtes (4) SELECT COUNT(*) FROM Etape GROUP BY numville HAVING numville = 1 Ici, GROUP BY est une solution compliquée et serait avantageusement remplacé par WHERE SELECT COUNT(*) FROM Etape WHERE numville = 1 2013-2014 Bases de données 45