Fonctions d'agrégation

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;
 max
-----
  46
(1 row)

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.