Comme la plupart des bases relationnel
PostgreSQL supporte les fonctions d'agrégation.
Une fonction d'agrégation est un résultat unique à partir de multiples
entrées-lignes.
Par exemple les agrégats pour calculer les
count, sum,
avg (moyenne), max (maximum) et
min (minimum) sur un ensemble de lignes.
Ainsi, nous pouvons trouver les plus hautes low-temperature avec :
SELECT max(temp_lo) FROM weather; |
Si nous voulons savoir dans quelle ville (ou villes) apparaissent ces
occurences, essayons :
SELECT city FROM weather WHERE temp_lo = max(temp_lo); WRONG |
mais ça ne marchera pas car l'agrégation
max n'a pas été utilisée dans la clause
WHERE. (Cette restriction existe parce que
la clause
WHERE détermine les lignes qui seront
utilisées au niveau agrégation).
Cependant, comme c'est souvent le cas,
la requête sera de nouveau énoncée pour accomplir le résultat attendu;
ici en faisant un
subquery :
SELECT city FROM weather
WHERE temp_lo = (SELECT max(temp_lo) FROM weather); |
city
---------------
San Francisco
(1 row) |
Ça marchera car le sub-select est un calcul indépendant
qui calcule ses propres agrégats séparément.
Les agrégats sont aussi très utilisées en association avec
les clauses GROUP BY. Par exemple, nous pouvons obtenir
les maxima des basses températures observées dans chaque ville avec :
SELECT city, max(temp_lo)
FROM weather
GROUP BY city; |
city | max
---------------+-----
Hayward | 37
San Francisco | 46
(2 rows) |
qui nous donne un affichage par ville. Chaque résultat est calculé
sur les lignes de la table appariant la ville.
On peut filtrer les lignes groupées avec
HAVING:
SELECT city, max(temp_lo)
FROM weather
GROUP BY city
HAVING max(temp_lo) < 40; |
city | max
---------+-----
Hayward | 37
(1 row) |
qui nous donne les mêmes résultats seulement pour les villes qui ont
des valeurs
temp_loinférieures à 40.
Enfin, si nous voulons uniquement les villes dont le nom commence par la lettre
"S", nous ferons :
SELECT city, max(temp_lo)
FROM weather
WHERE city LIKE 'S%'
GROUP BY city
HAVING max(temp_lo) < 40; |
Il est important de comprendre l'interaction entre les agrégats et
les clauses SQL WHERE et
HAVING.
La différence fondamentale entre WHERE et
HAVING est que : WHERE sélectionne
les entrées-ligne avant que les groupes et agrégats soient calculés
(ainsi il contrôle quelle ligne participera au calcul de l'agrégat),
tandis que HAVING sélectionne les groupes de lignes
après que les groupes et les agrégats soient calculés. Ainsi, la clause
WHERE ne doit pas contenir de fonction agrégat;
c'est un non sens d'essayer d'utiliser un agrégat pour déterminer
quelles lignes seront entrés dans les agrégats. D'autre part, les clauses
HAVINGcontiennent toujours des fonctions agrégat.
(Strictement parlant, nous pouvons écrire un clause
HAVING
qui n'utilise pas d'agrégats, mais c'est du gaspillage: la même condition
pourrait être utilisée plus efficacement au niveau
WHERE.)
Observons que nous pouvons appliquer la restriction nom de ville dans
WHERE, car il ne nécessite pas d'agrégat. Ce qui est
plus efficace que d'ajouter le restriction à HAVING,
parce que nous évitons le groupage et les calculs d'agrégats
pour toutes les lignes qui échouent sur la vérification
WHERE.