Funciones de Agregación
Como la mayoría del resto de los productos de bases de datos relacionales, PostgreSQL soporta funciones de Agregación (agrupación). Una función de agregado computa un resultado individual para múltiples filas de entrada. Por ejemplo, hay agregados para computar la cantidad (count), suma (sum), promedio (avg), máximo (max), y mínimo (min) sobre un conjunto de filas.
Como ejemplo, podemos encontrar la lectura de la temperatura mínima más alta con:
SELECT max(temp_min) FROM clima;
max ----- 46 (1 fila)
Si queremos saber la ciudad (o ciudades) donde ocurrió la lectura, podríamos probar con:
SELECT ciudad FROM weather WHERE temp_min = max(temp_min); -- INCORRECTO
pero esto no funcionará dado que el agregado max no funcionará en la clausula WHERE. (Esta limitación existe dado que la clausula WHERE determina que filas serán incluidas en el cálculo del agregado; por lo que obviamente necesita ser evaluada antes de que las funciones de agregado sean computadas.) Sin embargo, However, como suele ser frecuente la consulta puede ser reexpresada para lograr el resultado deseado, usando aquí una subconsulta:
SELECT ciudad FROM clima
WHERE temp_min = (SELECT max(temp_min) FROM clima);
ciudad --------------- San Francisco (1 fila)
Esto está OK ya que la subconsulta es una computación independiente de calcula su propio agregado separadamente de lo que está pasando en la consulta exterior.
Los agregados pueden ser muy útiles en combinación con las clausulas GROUP BY. Por ejemplo, podemos obtener la temperatura mínima más alta observada en cada ciudad con:
SELECT ciudad, max(temp_min)
FROM clima
GROUP BY ciudad;
ciudad | max ---------------+----- Hayward | 37 San Francisco | 46 (2 filas)
lo que nos da una fila de salida por ciudad. Cada resultado agregado es computado sobre las filas de la tabla que coinciden con cada ciudad. Podemos filtrar estas filas agrupadas usando HAVING:
SELECT ciudad, max(temp_min)
FROM clima
GROUP BY ciudad
HAVING max(temp_min) < 40;
ciudad | max ---------+----- Hayward | 37 (1 fila)
lo que nos da el mismo resultado pero solo para las ciudades que tienen todas sus valores de temp_min bajo 40. Finalmente, si solo nos interesa las ciudades cuyo nombre comiencen con "S", podríamos hacer:
SELECT ciudad, max(temp_min)
FROM clima
WHERE ciudad LIKE 'S%''''[ (1)]'''
GROUP BY ciudad
HAVING max(temp_min) < 40;
Nota 1
El operador LIKE hace una coincidencia de patrones y es explicada en Sección 9.7.
Es importante entender que la interacción entre agregados y las clausulas SQL WHERE y HAVING. La diferencia fundamental entre WHERE y HAVING es que: WHERE selecciona las filas de entrada antes que se agrupen y computen los agregados (entonces, controla que filas irán a la computación de agregados), en cambio HAVING selecciona las filas agrupadas después que los agregados son computados. Entonces, la clausula WHERE no debe contener funciones de agregado; no tiene sentido probar usar un agregado para determinar que filas serán la entrada de los agregados. Por otro lado, la clausula HAVING permite contener funciones de agregado. (Hablando estrictamente, esta permitido escribir una clausula que HAVING que no use agregados, pero es raramente útil. La misma condición puede ser usada más eficientemente en la etapa WHERE.)
En el ejemplo previo, podemos aplicar una restricción en el WHERE, dado que no necesita agregado. Esto es más eficiente que agregar la restricción a HAVING, ya que se evita hacer el agrupamiento y cálculos de agregados para todas las filas que fallen el chequeo del WHERE.
