Voltar para a lista de artigos Artigos
13 minutos de leitura

O que são funções agregadas em SQL, e como posso utilizá-las?

Os dados são a sua fonte de conhecimento. E graças às funções SQL agregadas, você pode extrair de seus dados o conhecimento preciso que precisa de forma eficiente. Leia mais adiante para saber mais.

As funções principais de agregação SQL são as seguintes:

  • COUNT(column_name | *) retorna o número de filas em uma tabela.
  • SUM(column_name) retorna a soma dos valores de uma coluna numérica.
  • AVG(column_name) retorna o valor médio de uma coluna numérica.
  • MIN(column_name) retorna o valor mínimo de uma coluna selecionada.
  • MAX(column_name) retorna o valor máximo de uma coluna selecionada.

Neste artigo, discutiremos cada um deles com exemplos. Você descobrirá o que acontece com NULLs e duplica quando submetido a funções agregadas. Além disso, explicaremos *, a palavra-chave DISTINCT, e a declaração CASE.

Vamos começar!

Como funcionam as funções agregadas

As funções agregadas SQL acumulam dados de várias linhas em uma única linha de resumo. O valor acumulado é baseado nos valores da coluna passada como argumento. Podemos agrupar as linhas usando uma cláusula GROUP BY e filtrá-las ainda mais usando uma cláusula HAVING.

Um exemplo padrão é encontrar o número de linhas em uma tabela. Aqui, agregamos todas as linhas da tabela Livros em uma linha.

SELECT * FROM Books;
IdAuthorTitlePrice
234Anthony MolinaroSQL Cookbook20.00
235Alan BeaulieuLearning SQL25.00
236Donald KnuthThings a Computer Scientist Rarely Talks About25.00
237Donald KnuthThe Art of Computer Programming27.00
SELECT COUNT(*) AS NumberOfBooks
FROM Books;
NumberOfBooks
4

Fácil, certo? Usando COUNT(*), você pode contar o número de todas as linhas.

Você também pode dar uma olhada em nossos outros artigos sobre funções agregadas SQL aqui e aqui.

O * Argumento para as funções agregadas

Se você me perguntar o que * significa em SQL, minha resposta é que significa para todos. Ela é comumente usada com uma declaração SELECT ao consultar todas as colunas de uma determinada tabela. Veja, por exemplo, SELECT * FROM Books, como acima.

O argumento * também pode ser usado com a função agregada COUNT(). Em seguida, ele conta todas as linhas de uma tabela. Tomemos, por exemplo, SELECT COUNT(*) as NumberOfBooks FROM Books, como acima.

Você pode agrupar os dados por alguma coluna ou mesmo por muitas colunas. Dê uma olhada no seguinte exemplo:

SELECT Author, COUNT(*) AS NumberOfBooks
FROM Books
GROUP BY Author;
AuthorNumberOfBooks
Anthony Molinaro1
Alan Beaulieu1
Donald Knuth2

Isto conta o número de livros por autor.

O argumento * se aplica apenas à função agregada COUNT(). Para outras funções agregadas, uma coluna específica, ou uma combinação de colunas, é necessária como argumento.

A palavra-chave DISTINCT

A palavra-chave DISTINCT diz ao banco de dados que não queremos considerar valores duplicados.

Por exemplo, COUNT(Author) nos dá o número de todos os autores presentes em uma tabela. Mas se o mesmo autor aparece muitas vezes em uma coluna, o autor é contado muitas vezes. Dê uma olhada nisto:

SELECT COUNT(Author) AS NumberOfAuthors
FROM books;
NumberOfAuthors
4

Veja? Conta-se quatro autores porque Donald Knuth é contado duas vezes.

O que acontece se adicionarmos a palavra-chave DISTINCT?

SELECT COUNT(DISTINCT Author) AS NumberOfAuthors
FROM Books;
NumberOfAuthors
3

Desta vez, usamos a palavra-chave DISTINCT. Agora, Donald Knuth é contado apenas uma vez. Ao usar a palavra-chave DISTINCT, COUNT() deve tomar uma coluna específica como argumento. Ela retorna o número de valores únicos armazenados nessa coluna.

Da mesma forma, podemos usar a palavra-chave DISTINCT com argumentos das funções agregadas de SUM() e AVG(). Abaixo, comparamos os resultados da execução da função SUM() com e sem a palavra-chave DISTINCT.

SELECT SUM(DISTINCT Price)
AS TotalDistinctPrice
FROM Books;
TotalDistinctPrice
72
	SELECT SUM(Price)
	AS TotalPrice
	FROM Books;
TotalPrice
97

Como você pode ver, quando você usa uma palavra-chave DISTINCT, os livros com o mesmo preço são considerados apenas uma vez na SUM(). Neste caso, faz mais sentido usar a função SUM() sem a palavra-chave DISTINCT.

Da mesma forma, ao calcular um preço médio, é melhor não usar a palavra-chave DISTINCT; devemos considerar cada preço tantas vezes quanto aparece na coluna. Veja o que acontece com AVG():

SELECT AVG(DISTINCT Price)
AS TotalDistinctAvg
FROM Books;
TotalDistinctAvg
24
	SELECT AVG(Price)
	AS TotalAvg
	FROM Books;
TotalAvg
24.25

Para as funções agregadas de MIN() e MAX(), a palavra-chave DISTINCT não faz diferença. Mas também não causa nenhum erro. Por quê? Vamos considerar um conjunto de números {1, 2, 2, 3, 4, 5, 5, 6}. Seus valores máximo e mínimo são 6 e 1, respectivamente. Com a palavra-chave DISTINCT, este conjunto se torna {1, 2, 3, 4, 5, 6}, portanto os valores máximo e mínimo ainda são os mesmos.

A declaração CASE

A declaração CASE categoriza e filtra os dados. É como um gatekeeper para o argumento de uma função agregada, decidindo quais os valores a serem deixados entrar. Vejamos alguns exemplos para ilustrar este conceito.

Na consulta seguinte, usamos uma declaração CASE como argumento para a função COUNT(). Ela conta apenas os livros cujo preço é superior a US$ 20,00.

SELECT COUNT(CASE WHEN Price > 20 THEN Price END)
AS NumberOfExpensiveBooks
FROM Books;
NumberOfExpensiveBooks
3

Uma declaração CASE também pode ser usada como argumento para outras funções agregadas. Na consulta abaixo, somamos os preços dos livros que custam exatamente $25,00. A declaração CASE dentro da função SUM() permite incluir na soma somente os livros cujo preço é de $25,00.

SELECT SUM(CASE WHEN Price = 25 THEN Price END)
AS BooksSum
FROM Books;
BooksSum
50

Agora, calculamos a média dos preços dos livros que custam menos de $26,00 na próxima consulta. A declaração CASE dentro da função AVG() permite incluir na média somente livros com preço abaixo de $26,00. A função AVG() é um argumento para a função ROUND(), portanto a saída da função AVG() é arredondada para duas casas decimais.

SELECT ROUND(AVG(CASE WHEN Price < 26 THEN Price END), 2)
AS BooksAvg
FROM Books;
BooksAvg
23.33

Na próxima consulta, encontramos o preço mínimo dos livros sobre SQL que custam menos de $26,00. A declaração CASE dentro da função MIN() permite que somente livros com um preço abaixo de $26,00 sejam incluídos no conjunto.

SELECT MIN(CASE WHEN Price < 26 AND Title LIKE '%SQL%' THEN Price END)
AS BooksMin
FROM Books;
BooksMin
20

A seguir, encontramos o preço máximo dos livros que custam menos de $25,00. A declaração CASE dentro da função MAX() permite que somente livros com preço abaixo de $25,00 sejam incluídos no conjunto.

SELECT MAX(CASE WHEN Price < 25 THEN Price END)
AS BooksMax
FROM Books;
BooksMax
20

Tenho certeza de que você já pode descobrir o resultado destas consultas!

O que acontece com os NULLs?

A resposta é simples. As funções agregadas SQL ignoram os valores NULL.

Vamos considerar uma atualização Books mesa. Desta vez, temos um preço NULL.

SELECT * FROM Books;
IdAuthorTitlePrice
234Anthony MolinaroSQL Cookbook20.00
235Alan BeaulieuLearning SQL25.00
236Donald KnuthThings a Computer Scientist Rarely Talks About25.00
237Donald KnuthThe Art of Computer ProgrammingNULL

COUNT(Price) agora retorna 3, não 4, e SUM(Price) retorna 70,00. NULLs são ignorados em ambos os casos.

Você também pode usar as funções agregadas com JOINs! Dê uma olhada em nosso artigo sobre o uso de funções agregadas SQL com JOINs para saber mais.

O Papel do HAVING e do GROUP BY com Funções Agregadas

É fácil entender o que uma cláusula HAVING faz se você estiver familiarizado com a cláusula WHERE. Uma cláusula HAVING filtra os valores de saída das funções agregadas. Uma cláusula GROUP BY permite dividir seus dados em grupos e encontrar um valor agregado para cada grupo.

Vejamos um exemplo.

SELECT Author, AVG(Price) AS AvgBookPrice
FROM Books
GROUP BY Author
HAVING AVG(Price) > 20;
AuthorAvgBookPrice
Alan Beaulieu25
Donald Knuth26

Nós agrupamos os dados pela coluna Autor usando uma cláusula GROUP BY. Em seguida, restringimos os valores de AVG(Price) a serem maiores que 20 usando uma cláusula HAVING.

Podemos tentar usar as cláusulas WHERE e HAVING em conjunto para ver a diferença entre elas.

SELECT Author, AVG(Price) AS AvgBookPrice
FROM Books
WHERE Author LIKE 'A%'
GROUP BY Author
HAVING AVG(Price) > 20;
AuthorAvgBookPrice
Alan Beaulieu25

A cláusula HAVING é freqüentemente confundida com a cláusula WHERE. Lembre-se que você não pode usar funções agregadas em uma cláusula WHERE. Certifique-se de obter prática suficiente e verifique nosso SQL HAVING Tutorial. Confira também nosso artigo sobre o uso de GROUP BY em SQL para obter ainda mais informações sobre a cláusula GROUP BY.

Funções agregadas SQL ou funções de janela SQL? Ou talvez ambas? Confira nosso artigo sobre as semelhanças e diferenças entre os dois!

Vamos praticar!

Não é suficiente apenas ler. SQL requer uma grande dose de prática. Vamos começar com alguns exemplos aqui para que você possa continuar por conta própria!

Antes de saltarmos para os exemplos, certifique-se de que você está claro sobre todos Fundamentos de SQL e Funções Comuns em SQL!

Exemplo de banco de dados

Abaixo está o projeto do banco de dados. Usaremos este banco de dados em nossos exemplos abaixo.

Base de dados de amostras

Vamos analisar o projeto do banco de dados, começando pela esquerda.

O Customers tabela armazena dados sobre os clientes. Sua chave primária é a coluna CustomerId. A coluna Customers e Orders As tabelas estão vinculadas utilizando a coluna CustomerId. A tabela de Pedidos armazena a data do pedido e a identificação do cliente que fez o pedido. Sua chave primária é a coluna OrderId. A ligação entre a Customers e Orders tabelas define a relação entre elas. Um cliente pode ter zero ou mais pedidos, mas um pedido pode ser atribuído a apenas um cliente.

O Orders e OrderDetails As tabelas estão vinculadas utilizando a coluna OrderId. A coluna Products e OrderDetails As tabelas estão vinculadas utilizando a coluna ProductId. A chave primária da OrderDetails A tabela é composta pelas colunas OrderId e ProductId.

Um pedido pode consistir em um ou mais produtos. Portanto, uma fila da tabela Orders tabela pode ser relacionada a uma ou mais fileiras do OrderDetails mesa. Além disso, um produto pode estar em zero ou mais pedidos. Portanto, uma fileira da Products tabela pode ser relacionada a zero ou mais filas do OrderDetails mesa.

Agora, vamos inserir alguns dados em nossas tabelas.

A Customers mesa:

CustomerIdFirstNameLastNameStreetHouseNoCityCountryEmailPhoneNo
1RachelHartleyBicetown Road602New YorkUSArh@email.com0123456789
2CaitlynRayFriedrichstrasse44BerlinGermanycr@email.com0987654321
3AndrewDuncanLairg Road38LondonNULLad@email.com0567432678
4TaylorJenkinsPark Row106EdinburghUKNULL0876345123
5BenHollandWilliams Avenue252Los AngelesUSAbh@email.com0987456789

A Orders tabela (a coluna de datas está no formato DD-MM-YYYY):

OrderIdCustomerIdOrderDate
45110-10-2021
46211-12-2020
47305-05-2021
48409-08-2021
495NULL
50102-06-2021
51207-07-2021

O OrderDetails mesa:

OrderIdProductIdQuantity
451002
451013
461001
471024
481013
481035
491042
501003
511011

A Products mesa:

ProductIdNameUnitPriceAvailableInStock
100Keyboard30.00300
101USB Drive20.00450
102Mouse20.00500
103Screen100.00450
104Laptop600.00200

Agora estamos prontos para começar com os exemplos.

Exemplos com COUNT()

Começamos com a Customers mesa. Vamos descobrir quantos clientes há por país.

SELECT Country, COUNT(CustomerId) AS NumberOfCustomers
FROM Customers
GROUP BY Country;
CountryNumberOfCustomers
NULL1
Germany1
UK1
USA2

Selecionamos todos os valores distintos a partir da coluna Country, incluindo o valor NULL. A coluna NumberOfCustomers armazena o número de clientes para cada valor da coluna Country.

O que acontece se usarmos a coluna Email como argumento para a função COUNT()?

SELECT Country, COUNT(Email) AS NumberOfCustomers
FROM Customers
GROUP BY Country;
CountryNumberOfCustomers
NULL1
Germany1
UK0
USA2

O valor da coluna NumberOfCustomers para o país "UK" se torna zero. Isto porque a coluna Email na Customers A tabela é NULL para este cliente.

Agora, vejamos um exemplo que usa as cláusulas GROUP BY e HAVING.

SELECT Country, COUNT(Email) AS NumberOfCustomersWithEmail
FROM Customers
WHERE Country IS NOT NULL
GROUP BY Country
HAVING COUNT(Email) > 1;
CountryNumberOfCustomersWithEmail
USA2

Como antes, selecionamos os valores da coluna País e obtemos a contagem de clientes com e-mails por país. Na cláusula WHERE, afirmamos que não consideramos os valores NULL para a coluna Country. Em seguida, agrupamos nossos dados por Country. Finalmente, restringimos os valores da coluna NumberOfCustomersWithEmail a serem maiores que 1 com uma cláusula HAVING.

Exemplos com SUM()

Vamos verificar quanto valem todos os produtos disponíveis.

SELECT SUM(UnitPrice * AvailableInStock) AS AllProductsValue
FROM Products;
AllProductsValue
193000

Aqui, a função agregada SUM() cria um valor de UnitPrice * AvailableInStock para cada linha e depois soma todos esses valores.

Digamos que cada pedido de valor superior a US$ 100,00 se qualifica para um desconto. Queremos saber quais pedidos se qualificam para o desconto.

SELECT OrderId,
       CASE WHEN OrderValue > 100 THEN 1 ELSE 0 END
       AS QualifiesForDiscount
FROM
     ( SELECT aod.OrderId AS OrderId,
              SUM(aod.Quantity * ap.UnitPrice) AS OrderValue
       FROM Products ap
       JOIN OrderDetails aod
       ON ap.ProductId = aod.ProductId
       GROUP BY aod.OrderId );
OrderIdQualifiesForDiscount
451
460
470
481
491
500
510

A consulta interna seleciona todos os valores da coluna OrderId e calcula o valor de cada pedido usando a função SUM(). A consulta externa usa uma declaração CASE para decidir se o pedido se qualifica para um desconto (1) ou não (0).

Agora, digamos que definimos todos os produtos com um preço unitário superior a US$ 90,00 para serem caros. Vamos descobrir o valor total de todos os produtos caros em estoque.

SELECT
    SUM(CASE WHEN UnitPrice > 90 THEN UnitPrice * AvailableInStock END)
    AS ExpensiveProductsValue
FROM Products;
ExpensiveProductsValue
165000

Passamos uma declaração CASE como argumento para a função SUM(). Este argumento garante que somente as linhas com o valor UnitPrice superior a $90,00 sejam consideradas. Fora isso, este exemplo é bastante similar ao primeiro desta seção.

Exemplos com AVG()

Vamos verificar qual é o preço médio de um pedido.

SELECT AVG(OrderValue) AS AvgOrderValue
FROM
     ( SELECT aod.OrderId AS OrderId,
              SUM(aod.Quantity * ap.UnitPrice) AS OrderValue
       FROM Products ap
       JOIN OrderDetails aod
       ON ap.ProductId = aod.ProductId
       GROUP BY aod.OrderId );

AvgOrderValue
300

A consulta interna gera o valor total do pedido para cada pedido. A consulta externa calcula o valor médio de um pedido.

Também podemos descobrir a quantidade média encomendada por produto.

SELECT ROUND(AVG(Quantity), 2) AS AvgOrderQuantity
FROM OrderDetails;
AvgOrderQuantity
2.67

Em média, nossos clientes compram entre 2 e 3 itens de um determinado produto em um pedido.

Vamos ver o que muda quando consideramos apenas os valores únicos da coluna Quantity.

SELECT ROUND(AVG(DISTINCT Quantity), 2) AS AvgOrderQuantity
FROM OrderDetails;
AvgOrderQuantity
3

O valor de saída muda, porque não consideramos mais valores duplicados que aparecem na coluna Quantity do OrderDetails mesa.

Exemplos com MAX() e MIN()

Por último, mas não menos importante! As funções MAX() e MIN() são bastante simples. Vamos descobrir as encomendas mais antigas e as mais recentes.

SELECT MIN(OrderDate) AS EarliestOrder,
       MAX(OrderDate) AS LatestOrder
FROM Orders;
EarliestOrderLatestOrder
11-12-202010-10-2021

A função MIN() retorna a data mais antiga, e a função MAX() retorna a data mais recente.

Também podemos identificar os produtos mais baratos e os mais caros. Você pode pesquisar a Products tabela para fazer isso.

SELECT MIN(UnitPrice) AS CheapestProductPrice,
       MAX(UnitPrice) AS MostExpensiveProductPrice
FROM Products;
CheapestProductPriceMostExpensiveProductPrice
20600

Vamos descobrir quantos pedidos existem por cliente, depois obtenhamos o número mínimo e máximo de pedidos por cliente.

SELECT MIN(NumberOfOrders) AS MinNumberOfOrders,
       MAX(NumberOfOrders) AS MaxNumberOfOrders
FROM
     ( SELECT CustomerId,
              COUNT(OrderID) AS NumberOfOrders
       FROM Orders
       GROUP BY CustomerId );
MinNumberOfOrdersMaxNumberOfOrders
12

A consulta interna seleciona a coluna CustomerId e o número total de pedidos feitos por um determinado cliente. A função COUNT(OrderId) conta o número de pedidos por cliente. A seguir, agrupamos nossos dados pela coluna CustomerId usando uma cláusula GROUP BY. Nesta etapa, a função COUNT(OrderId) conta os pedidos por cliente e não para todos os clientes em conjunto. A consulta externa seleciona os valores mínimo e máximo da coluna NumberOfOrders a partir da consulta interna.

Funções Agregadas SQL como Ferramenta Essencial na Ciência dos Dados

Usando funções agregadas, podemos facilmente encontrar respostas a perguntas específicas, tais como quantos clientes existem ou qual é o preço médio de um pedido. As funções agregadas SQL nos permitem analisar os dados de forma eficiente.

Estas funções principais de agregação SQL são muito úteis na ciência dos dados. Com elas, é possível organizar os dados da maneira que se deseja e extrair as informações de que se precisa.

Revisamos muitos exemplos com as funções agregadas COUNT(), SUM(), AVG(), MIN(), e MAX(). Também cobrimos exemplos de *, a palavra-chave DISTINCT, e a declaração CASE como argumentos para agregar funções. Agora, você está pronto para criar seu banco de dados e praticar um pouco mais!