Capítulo 12: Funções de Agregação e Agrupamento: GROUP BY e HAVING

🎯 Objetivo da Aula

Nesta aula de conclusão do Módulo 3, você aprenderá a transformar milhares de linhas de transporte em indicadores sintéticos de Business Intelligence (BI) diretamente na camada do SGBD. No laboratório de informática, você dominará as cinco funções universais de agregação do SQL (COUNT, SUM, AVG, MIN e MAX), aprenderá a estruturar agrupamentos executivos com a cláusula GROUP BY e compreenderá a distinção vital entre filtrar linhas individuais com WHERE e filtrar grupos consolidados com HAVING.

Ao final desta aula, você será capaz de responder instantaneamente a perguntas complexas da diretoria da FastLog S.A., como faturamento consolidado por região, ticket médio de frete por cliente e peso total transportado por rota.


🏢 Cenário Prático (FastLog S.A.)

Empresa: FastLog Transportes & Logística Integrada S.A.
Problema: Toda sexta-feira às 17h00, o comitê de diretoria se reúne para avaliar o desempenho das filiais. O diretor financeiro exigia saber: “Qual é o faturamento total, o frete médio e a quantidade de viagens realizadas por cada filial de destino, exibindo apenas as filiais que superaram a meta de R$ 150.000,00 no mês?”. O assistente de controladoria passava 3 horas exportando tabelas, criando planilhas dinâmicas no Excel e montando fórmulas manuais. Em duas ocasiões, ele esqueceu de atualizar o intervalo da tabela dinâmica e apresentou números de faturamento defasados, levando a empresa a tomar decisões erradas sobre abertura de novas rotas.
Sua Missão: Como especialista em SQL e BI, você construirá uma consulta analítica agregada com GROUP BY e HAVING que processa toda a base de fretes e entrega os indicadores consolidados na tela em 0,04 segundo, com precisão matemática absoluta.


🧠 Fundamentos: A Teoria Traduzida

1. As 5 Funções Universais de Agregação

flowchart TD
    DADOS["📦 Centenas de Ordens de Frete Individuais<br/>(Linha por Linha)"] --> AGREGACAO{"⚙️ Funções de Agregação SQL"}
    
    AGREGACAO --> C1["COUNT() ➔ Contagem de Viagens"]
    AGREGACAO --> C2["SUM() ➔ Faturamento Total (R$)"]
    AGREGACAO --> C3["AVG() ➔ Ticket Médio por Frete (R$)"]
    AGREGACAO --> C4["MIN() ➔ Menor Tarifa Praticada (R$)"]
    AGREGACAO --> C5["MAX() ➔ Carga Mais Valiosa Despachada (R$)"]

    style DADOS fill:#1a365d,stroke:#fff,stroke-width:2px,color:#fff
    style AGREGACAO fill:#e67e22,stroke:#fff,stroke-width:2px,color:#fff
    style C1 fill:#2980b9,stroke:#fff,stroke-width:1px,color:#fff
    style C2 fill:#27ae60,stroke:#fff,stroke-width:1px,color:#fff
    style C3 fill:#8e44ad,stroke:#fff,stroke-width:1px,color:#fff
    style C4 fill:#744210,stroke:#fff,stroke-width:1px,color:#fff
    style C5 fill:#c0392b,stroke:#fff,stroke-width:1px,color:#fff

2. A Cláusula GROUP BY e sua Regra de Ouro

Quando você usa uma função como SUM(Valor_Frete), o Access calcula a soma de toda a tabela em uma única célula. Para que o somatório seja calculado por Filial, por Estado ou por Motorista, usamos a cláusula GROUP BY:

1
2
3
4
SELECT tbl_Clientes.UF, SUM(tbl_OrdensFrete.Valor_Frete) AS TotalFaturado
FROM tbl_Clientes 
INNER JOIN tbl_OrdensFrete ON tbl_Clientes.ID_Cliente = tbl_OrdensFrete.ID_Cliente
GROUP BY tbl_Clientes.UF;

⚠️ A Regra Inviolável do GROUP BY:

Qualquer coluna presente na lista do SELECT que NÃO ESTEJA envolvida por uma função agregadora (COUNT, SUM, etc.) DEVE CONSTAR OBRIGATORIAMENTE na cláusula GROUP BY. Se você esquecer, o SGBD emitirá um erro de sintaxe imediato!

3. A Diferença Crucial: WHERE vs. HAVING

Muitos analistas confundem essas duas cláusulas de filtro:

CritérioCláusula WHERECláusula HAVING
Momento de AplicaçãoAntes do agrupamentoDepois do agrupamento
Escopo de AçãoFiltra linhas individuais da tabelaFiltra métricas agregadas de grupos
Pode usar funções agregadas?NUNCA! (WHERE SUM(...) > 10 causa erro!)SIM! (HAVING SUM(Valor_Frete) > 150000)
Exemplo de AplicaçãoWHERE Status_Ordem = 'Entregue'HAVING COUNT(ID_OrdemFrete) >= 5

📖 Exemplo Guiado: Passo a Passo no Laboratório

Abra o arquivo FastLog_Database.accdb. Vamos construir o painel analítico de faturamento por estado.

Passo 1: Abrindo a Consulta em Modo SQL

  1. Acesse Criar ➔ Design da Consulta.
  2. Feche a janelinha Adicionar Tabelas.
  3. Clique no botão Modo SQL no canto superior esquerdo.
  4. Limpe o editor em branco.

🛠️ Prática Obrigatória 1: Faturamento e Ticket Médio por Cliente com GROUP BY

Você criará o ranking executivo que totaliza os fretes contratados por cada cliente corporativo.

Passo a Passo no Computador:

  1. Digite o script SQL analítico abaixo:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    SELECT 
        tbl_Clientes.Razao_Social AS [Cliente Corporativo],
        tbl_Clientes.Cidade,
        tbl_Clientes.UF,
        COUNT(tbl_OrdensFrete.ID_OrdemFrete) AS [Qtd de Viagens],
        SUM(tbl_OrdensFrete.Valor_Frete) AS [Faturamento Total (R$)],
        AVG(tbl_OrdensFrete.Valor_Frete) AS [Ticket Médio (R$)],
        MAX(tbl_OrdensFrete.Valor_Frete) AS [Maior Frete (R$)]
    FROM tbl_Clientes
    INNER JOIN tbl_OrdensFrete ON tbl_Clientes.ID_Cliente = tbl_OrdensFrete.ID_Cliente
    GROUP BY tbl_Clientes.Razao_Social, tbl_Clientes.Cidade, tbl_Clientes.UF
    ORDER BY SUM(tbl_OrdensFrete.Valor_Frete) DESC;
  2. Clique no botão com a exclamação vermelha ! Executar.
  3. Análise dos Indicadores Gerenciais:
    • Observe que cada cliente aparece exatamente uma vez na lista.
    • Ao lado de cada empresa, você enxerga o volume de fretes contratados, a receita bruta total gerada, o valor médio pago por viagem e o frete recorde daquele cliente!
    • A lista está perfeitamente ordenada dos maiores clientes (Key Accounts) para os menores.
  4. Salve a consulta como: qry_DesempenhoClientesBI.

✅ Resultado Esperado (Prática 1):

A consulta consolida centenas de registros operacionais em um sumário analítico perfeito de clientes com 4 métricas calculadas simultaneamente.


🛠️ Prática Obrigatória 2: Filtrando Metas Consolidadas com HAVING

Agora você responderá à exigência da diretoria: filtrar apenas as unidades ou clientes cujo faturamento total supere a meta de R$ 50.000,00 e que tenham realizado pelo menos 2 viagens.

Passo a Passo no Computador:

  1. Abra qry_DesempenhoClientesBI no Modo SQL.
  2. Adicione a cláusula HAVING logo após o GROUP BY e antes do ORDER BY:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    SELECT 
        tbl_Clientes.Razao_Social AS [Cliente Corporativo],
        tbl_Clientes.Cidade,
        tbl_Clientes.UF,
        COUNT(tbl_OrdensFrete.ID_OrdemFrete) AS [Qtd de Viagens],
        SUM(tbl_OrdensFrete.Valor_Frete) AS [Faturamento Total (R$)],
        AVG(tbl_OrdensFrete.Valor_Frete) AS [Ticket Médio (R$)]
    FROM tbl_Clientes
    INNER JOIN tbl_OrdensFrete ON tbl_Clientes.ID_Cliente = tbl_OrdensFrete.ID_Cliente
    GROUP BY tbl_Clientes.Razao_Social, tbl_Clientes.Cidade, tbl_Clientes.UF
    HAVING SUM(tbl_OrdensFrete.Valor_Frete) >= 50000 
       AND COUNT(tbl_OrdensFrete.ID_OrdemFrete) >= 2
    ORDER BY SUM(tbl_OrdensFrete.Valor_Frete) DESC;
  3. Execute a consulta.
  4. Análise da Filtragem por Grupo:
    • Clientes casuais ou com faturamento inferior à meta de R$ 50.000,00 são automaticamente eliminados da tela.
    • O relatório exibe com exclusividade os clientes de alta rentabilidade que atingiram a meta corporativa!
  5. Salve a consulta como: qry_ClientesMetaAtingida.

✅ Resultado Esperado (Prática 2):

A consulta utiliza a cláusula HAVING para filtrar os grupos sumarizados em tempo real, fornecendo à diretoria a lista precisa de parceiros comerciais estratégicos.


📤 Instruções de Entrega (Microsoft Teams)

  1. Salve o banco de dados e feche o Access.
  2. Nomeie o arquivo: FastLog_BD_Cap12_SeuNome_SeuSobrenome.accdb.
  3. Acesse o Microsoft Teams na sua turma técnica.
  4. Abra a tarefa: “Banco de Dados - Cap 12: Funções Agregadas GROUP BY e HAVING”.
  5. Anexe o seu arquivo .accdb e conclua o envio clicando em Entregar (Turn In).

💡 Checkpoint de Gestão & TI

Parabéns pela conclusão do Módulo 3: Linguagem SQL Corporativa! Você agora domina a ferramenta analítica mais requisitada pelo mercado de tecnologia e negócios. Você aprendeu a filtrar linhas com WHERE, a cruzar tabelas com INNER/LEFT JOIN e a consolidar indicadores estratégicos com GROUP BY/HAVING. No Módulo 4: Formulários Operacionais & Relatórios Gerenciais, você aprenderá a construir interfaces gráficas ergonômicas para os operadores da FastLog digitarem dados sem risco de erro humano!


🔥 Desafio de Fixação: Consolidação de Peso e Frete por Rota Logística

O gerente de manutenção de rodovias precisa auditar o desgaste das estradas e a rentabilidade do transporte por rota.

Escreva uma consulta SQL no Access que atenda aos seguintes requisitos:

  1. Cruze as tabelas tbl_Rotas e tbl_OrdensFrete via INNER JOIN usando o campo Codigo_Rota.
  2. Agrupe os dados por Codigo_Rota e Descricao_Trajeto.
  3. Calcule:
    • A quantidade de viagens realizadas (COUNT(ID_OrdemFrete) AS [Total_Viagens]).
    • O peso total em toneladas transportado (SUM(Peso_Liquido_Kg) / 1000 AS [Total_Toneladas]).
    • A receita bruta total da rota (SUM(Valor_Frete) AS [Receita_Total_Rota]).
  4. Filtre com HAVING apenas rotas que já tenham acumulado mais de 20 toneladas transportadas (SUM(Peso_Liquido_Kg) > 20000).
  5. Ordene o resultado pelo peso total em ordem decrescente (DESC).
  6. Salve com o nome: qry_AuditoriaRentabilidadeRotas.

🔑 Revelar Gabarito Oficial e Material de Apoio da Aula (Clique para expandir)
💡 Incentivo Pedagógico: Tente resolver as práticas e o desafio de fixação por conta própria antes de abrir o gabarito. Seus erros e tentativas durante o laboratório são a chave para a consolidação real do aprendizado!

Código SQL Oficial do Desafio de Fixação:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
SELECT 
    tbl_Rotas.Codigo_Rota,
    tbl_Rotas.Descricao_Trajeto,
    COUNT(tbl_OrdensFrete.ID_OrdemFrete) AS Total_Viagens,
    (SUM(tbl_OrdensFrete.Peso_Liquido_Kg) / 1000) AS Total_Toneladas,
    SUM(tbl_OrdensFrete.Valor_Frete) AS Receita_Total_Rota
FROM tbl_Rotas
INNER JOIN tbl_OrdensFrete ON tbl_Rotas.Codigo_Rota = tbl_OrdensFrete.Codigo_Rota
GROUP BY tbl_Rotas.Codigo_Rota, tbl_Rotas.Descricao_Trajeto
HAVING SUM(tbl_OrdensFrete.Peso_Liquido_Kg) > 20000
ORDER BY (SUM(tbl_OrdensFrete.Peso_Liquido_Kg) / 1000) DESC;

📥 Download dos Scripts desta Aula:
Baixe o arquivo de script Capitulo_12.sql ou o pacote compactado (.zip) com os comandos SQL e esquemas da aula.


📝 Atividade Extra: Questionário de Fixação (Caderno)

Instruções: Responda no caderno, de próprio punho, as 10 perguntas reflexivas abaixo com base no conteúdo deste capítulo. Ao concluir, apresente o caderno ao professor para conferência e visto.

  1. Cite as cinco funções canônicas de agregação da linguagem SQL e explique sucintamente o papel de cada uma.
  2. Qual é a finalidade da cláusula GROUP BY em uma instrução SQL?
  3. Enuncie a Regra de Ouro do GROUP BY referente às colunas projetadas no comando SELECT.
  4. O que acontece quando tentamos executar uma consulta SQL com campos descritivos no SELECT sem incluí-los no GROUP BY?
  5. Explique a diferença fundamental de momento e finalidade entre a cláusula WHERE e a cláusula HAVING.
  6. Por que o comando WHERE SUM(Valor_Frete) > 10000 causa um erro imediato no SGBD?
  7. No Cenário Prático da FastLog, qual foi o impacto negativo das planilhas dinâmicas manuais do assistente nas reuniões de diretoria?
  8. Como a cláusula HAVING permite à empresa identificar apenas os parceiros que atingiram as metas comerciais?
  9. Na Prática Obrigatória 1, qual foi a função agregadora utilizada para descobrir o frete de maior valor contratado por cada cliente?
  10. No Desafio de Fixação, como a fórmula (SUM(Peso_Liquido_Kg) / 1000) conseguiu converter os dados gravados em quilos para toneladas diretamente no SQL?