2.7. Funções de agregação

Como a maioria dos produtos de banco de dados relacional, o PostgreSQL suporta funções de agregação. Uma função de agregação computa um único resultado para várias linhas de entrada. Por exemplo, existem funções de agregação para contar (count), somar (sum), calcular a média (avg), o valor máximo (max) e o valor mínimo (min) para um conjunto de linhas.

Para servir de exemplo, é possível encontrar a maior temperatura mínima observada em qualquer lugar usando

SELECT max(temp_min) FROM clima;

 max
-----
  46
(1 linha)

Se for desejado saber a cidade (ou cidades) onde esta temperatura ocorreu pode-se tentar usar

SELECT cidade FROM clima WHERE temp_min = max(temp_min);     ERRADO

mas não vai funcionar, porque a função de agregação max não pode ser usada na cláusula WHERE (Esta restrição existe porque a cláusula WHERE determina quais linhas serão incluídas no cálculo da agregação e, neste caso, teria que ser avaliada antes das funções de agregação serem computadas). Entretanto, como é geralmente o caso, a consulta pode ser reformulada para obter o resultado pretendido, o que será feito por meio de uma subconsulta:

SELECT cidade FROM clima
    WHERE temp_min = (SELECT max(temp_min) FROM clima);

     cidade
---------------
 São Francisco
(1 linha)

Isto está correto porque a subconsulta é uma ação independente, que calcula sua agregação isoladamente do que está acontecendo na consulta externa.

As agregações também são muito úteis em combinação com a cláusula GROUP BY. Por exemplo, pode ser obtida a maior temperatura mínima observada em cada cidade usando

SELECT cidade, max(temp_min)
    FROM clima
    GROUP BY cidade;

     cidade      | max
-----------------+-----
 Hayward         |  37
 São Francisco   |  46
(2 linhas)

produzindo uma linha de saída para cada cidade. Cada resultado da agregação é computado sobre as linhas da tabela correspondendo a uma cidade. As linhas agrupadas podem ser filtradas utilizando a cláusula HAVING

SELECT cidade, max(temp_min)
    FROM clima
    GROUP BY cidade
    HAVING max(temp_min) < 40;

  cidade   | max
-----------+-----
 Hayward   |  37
(1 linha)

que mostra os mesmos resultados, mas apenas para as cidades que possuem os valores de max(temp_min) abaixo de 40. Para concluir, se desejarmos somente as cidades com nome começando pela letra "S" podemos escrever:

SELECT cidade, max(temp_min)
    FROM clima
    WHERE cidade LIKE 'S%'(1)
    GROUP BY cidade
    HAVING max(temp_min) < 40;
(1)
O operador LIKE faz correspondência com padrão, sendo explicado na Seção 9.7.

É importante compreender a interação entre as agregações e as cláusulas WHERE e HAVING do SQL. A diferença fundamental entre WHERE e HAVING é esta: WHERE seleciona as linhas de entrada antes dos grupos e agregações serem computados (portanto, controla quais linhas irão para o computo da agregação), enquanto HAVING seleciona linhas de grupo após os grupos e agregações serem computados. Portanto, a cláusula WHERE não pode conter funções de agregação; não faz sentido tentar utilizar uma agregação para determinar quais linhas serão a entrada da agregação. Por outro lado, a cláusula HAVING sempre contém funções de agregação (A rigor, é permitido escrever uma cláusula HAVING que não possui agregação, mas raramente é útil: A mesma condição pode ser utilizada de forma mais eficiente no estágio do WHERE).

No exemplo anterior, a restrição do nome da cidade pode ser aplicada na cláusula WHERE, porque não necessita de nenhuma agregação. É mais eficiente que colocar a restrição na cláusula HAVING, porque evita realizar os procedimentos de agrupamento e agregação em todas as linhas que não atendem a cláusula WHERE.

SourceForge.net Logo CSS válido!