Pular para o conteúdo
Fynx
Business Intelligence12 min de leitura

Power Query: como agrupar linhas (Group By)

Guia prático de Power Query agrupar linhas (Group By): agregações, agrupamento por várias colunas, saídas múltiplas e quando agregar na consulta ou em DAX.

F
Fynx

Quando a tabela chega detalhada demais para o relatório

Você importou uma base de vendas com 4 milhões de linhas, uma por item de nota fiscal, mas o relatório só precisa de faturamento por região e por mês. Ou puxou um log de eventos e o que interessa é a contagem de acessos por usuário. Nos dois casos o caminho é o mesmo: consolidar muitas linhas em poucas, com algum número resumido no meio. É exatamente isso que o recurso de Power Query agrupar linhas (Group By) faz, e é uma das transformações mais usadas em qualquer projeto de BI sério.

O problema é que quase todo mundo aprende só o clique básico, monta uma soma e nunca mais olha para as opções avançadas. Neste artigo vou mostrar o Group By de ponta a ponta: as agregações básicas, o agrupamento por várias colunas, o agrupamento avançado com múltiplas saídas e, o mais importante na prática, quando vale a pena agregar na consulta e quando é melhor deixar o grão fino e resolver em DAX.

Power Query agrupar linhas (Group By) é trabalho da função Table.Group

Toda vez que você usa Página Inicial, Agrupar Por na interface, o Power Query gera por trás uma chamada à função Table.Group na linguagem M. Vale a pena conhecer essa função direto, porque a interface esconde parte do poder dela. A assinatura simplificada é assim:

Table.Group(
    tabela as table,
    chave as any,          // colunas que definem os grupos
    colunasAgregadas as list  // as novas colunas de resumo
)

A chave é a lista de colunas que define o grão do resultado. As colunas agregadas são uma lista de listas, onde cada item traz o nome da nova coluna, a operação e, de forma opcional, o tipo de dado. Um exemplo mínimo, somando o valor por região:

= Table.Group(
    Origem,
    {"Regiao"},
    {
        {"Faturamento", each List.Sum([Valor]), type number}
    }
)

O resultado tem uma linha por região e uma coluna Faturamento com a soma. Simples. O ganho de entender a função é que você consegue editar a barra de fórmulas na mão e ajustar qualquer detalhe sem depender do assistente.

As agregações básicas cobrem 90% dos casos

Na tela de agrupamento, o Power Query oferece um conjunto fixo de operações. Cada uma corresponde a uma função da linguagem M aplicada a uma coluna. A tabela abaixo mostra o mapa direto entre o que você escolhe na interface e o código M gerado:

Operação na interfaceFunção M geradaO que retorna
SomaList.Sum([Coluna])Total da coluna no grupo
Contagem de LinhasTable.RowCount(_)Quantidade de linhas do grupo
Contagem de Valores DistintosList.Count(List.Distinct([Coluna]))Quantos valores únicos há
MínimoList.Min([Coluna])Menor valor do grupo
MáximoList.Max([Coluna])Maior valor do grupo
MédiaList.Average([Coluna])Média aritmética do grupo
MedianaList.Median([Coluna])Valor central do grupo

Na prática, misturar várias dessas operações no mesmo agrupamento é o mais comum. Imagine que você queira, por região, o faturamento total, a quantidade de pedidos, o menor e o maior ticket e o ticket médio. Tudo de uma vez:

= Table.Group(
    Origem,
    {"Regiao"},
    {
        {"Faturamento", each List.Sum([Valor]), type number},
        {"Qtd Pedidos", each Table.RowCount(_), Int64.Type},
        {"Menor Ticket", each List.Min([Valor]), type number},
        {"Maior Ticket", each List.Max([Valor]), type number},
        {"Ticket Medio", each List.Average([Valor]), type number}
    }
)

Repare em dois detalhes que fazem diferença. Primeiro, a contagem de linhas usa Table.RowCount(_), onde o _ representa a subtabela de cada grupo, e não uma coluna específica. Segundo, sempre declare o tipo no terceiro elemento de cada lista (type number, Int64.Type). Isso evita que o Power Query devolva colunas como tipo any, o que atrapalha o carregamento no modelo e o desempenho depois.

Um cuidado clássico é com valores nulos. List.Sum e List.Average ignoram nulos por padrão, então uma média pode sair maior do que você espera. Se o nulo precisa contar como zero, trate a coluna antes de agrupar.

Agrupar por várias colunas muda o grão do resultado

Até aqui usamos uma única chave. Mas o grão de saída é definido pela combinação de colunas que você coloca na chave. Agrupar só por região dá uma linha por região. Agrupar por região e categoria dá uma linha por cada par região mais categoria existente na base. Quanto mais colunas na chave, mais fino o grão e mais linhas no resultado.

Para agrupar por várias colunas, basta listar todas na chave:

= Table.Group(
    Origem,
    {"Regiao", "Categoria", "Ano"},
    {
        {"Faturamento", each List.Sum([Valor]), type number},
        {"Qtd Pedidos", each Table.RowCount(_), Int64.Type}
    }
)

Aqui o resultado tem uma linha por combinação de região, categoria e ano. É a forma mais rápida de montar uma tabela pré-agregada no grão que o relatório precisa. Só tome cuidado: se você inclui uma coluna de alta cardinalidade na chave, como código do cliente ou data cheia com hora, o agrupamento perde o efeito de consolidação e você acaba com quase o mesmo número de linhas do início. A regra é escolher para a chave apenas as dimensões pelas quais você realmente vai analisar.

O agrupamento avançado entrega mais de uma lógica na mesma passada

Aqui mora a parte que a maioria não usa. Na tela de agrupamento existe a opção Avançado, que libera dois recursos: adicionar várias agregações com colunas diferentes e, principalmente, a operação Todas as Linhas. Essa operação guarda a subtabela inteira de cada grupo dentro de uma célula, e é o que destrava os casos mais interessantes.

O exemplo mais útil é manter o detalhe junto com o resumo. Você agrupa por cliente, calcula o faturamento e, ao mesmo tempo, guarda todas as linhas daquele cliente numa coluna do tipo tabela:

= Table.Group(
    Origem,
    {"Cliente"},
    {
        {"Faturamento", each List.Sum([Valor]), type number},
        {"Pedidos", each Table.RowCount(_), Int64.Type},
        {"Detalhe", each _, type table}
    }
)

A coluna Detalhe fica com um ícone de tabela em cada linha. Você pode expandir de volta quando quiser, ou usar essa subtabela para cálculos que a interface não oferece direto. Por exemplo, pegar o valor da última compra de cada cliente, algo que nenhuma operação padrão faz:

= Table.Group(
    Origem,
    {"Cliente"},
    {
        {"Faturamento", each List.Sum([Valor]), type number},
        {"Ultima Compra", each List.Max([Data]), type date},
        {"Valor da Ultima Compra",
            each List.Last(
                Table.SelectRows(_, (r) => r[Data] = List.Max([Data]))[Valor]
            ),
            type number}
    }
)

O que está acontecendo: dentro de cada grupo, o _ é a subtabela do cliente, filtramos as linhas cuja data é a máxima e pegamos o valor. Esse tipo de agregação condicional é impossível pelos botões, mas trivial quando você entende que cada célula pode carregar uma tabela inteira.

Outro padrão frequente do agrupamento avançado é gerar concatenações. Suponha que você queira, por pedido, a lista de produtos separada por vírgula:

= Table.Group(
    Origem,
    {"Pedido"},
    {
        {"Produtos", each Text.Combine(List.Distinct([Produto]), ", "), type text},
        {"Itens", each Table.RowCount(_), Int64.Type}
    }
)

Esse é o tipo de transformação que sem o Group By avançado viraria uma gambiarra de várias etapas.

Agregar cedo reduz volume, mas você perde granularidade

Agora a decisão que separa quem faz ETL de quem faz ETL bem feito. Toda vez que você agrupa na consulta, troca muitas linhas por poucas: reduz o volume no modelo, acelera a atualização e deixa a tabela mais leve. Parece só vantagem, mas tem um custo silencioso: você perde a granularidade original, e granularidade perdida na consulta não volta. Se amanhã o negócio pedir uma análise por dia da semana e você agregou por mês, não tem DAX que resolva, o dado fino já não existe no modelo.

Por isso a decisão não é sobre gosto, é sobre flexibilidade futura. A boa prática em modelagem dimensional é manter a fato no menor grão que faz sentido e deixar as agregações para o DAX, que recalcula conforme o usuário filtra. Agregar na consulta faz sentido quando o grão fino é grande demais, não traz valor analítico e o resultado agregado é estável. A tabela abaixo resume os dois cenários:

CritérioAgregar na consulta (Power Query)Manter o grão e agregar em DAX
Volume de dadosReduz linhas na origem, atualização mais leveMantém todas as linhas no modelo
Flexibilidade de análiseBaixa, o grão fica congeladoAlta, o usuário fatia como quiser
Detalhe (drill-down)Perde o detalhe finoPreserva o detalhe até a linha
ManutençãoMuda a consulta a cada novo grãoUma medida serve vários cortes
Melhor quandoBase gigante, grão fino sem valorPrecisa de flexibilidade e drill

Na prática o desenho mais comum é híbrido. Você mantém a fato no grão de item ou transação e, quando um relatório específico consome só dados consolidados e pesados, cria uma tabela de agregação separada com o Group By, sem jogar fora a fato detalhada. Você fica com performance onde precisa e granularidade onde importa. Para aprofundar o lado do modelo, vale ler nosso material de boas práticas de modelagem e DAX no Power BI.

O Group By faz folding quando a fonte é um banco SQL

Um ponto técnico que muda o desempenho de projeto grande: quando a origem é um banco relacional, como SQL Server ou Postgres, o Power Query tenta empurrar a transformação para a fonte. Isso se chama query folding. Em vez de trazer milhões de linhas e agrupar na sua máquina, o Power Query traduz o Group By para um GROUP BY em SQL e o banco devolve só o resultado agregado. Menos tráfego, menos memória, atualização mais rápida.

O agrupamento é uma das operações que costuma sofrer folding sem problema, desde que os passos anteriores também sejam dobráveis. Se você colocou antes uma etapa que quebra o folding, como uma coluna com função exclusiva de M ou um passo de índice, o agrupamento passa a rodar localmente e você perde o ganho. Vale conferir com o botão direito no passo, opção Exibir Consulta Nativa. Se ela estiver disponível, o folding está de pé até ali.

Alguns pontos que ajudam a preservar o folding no agrupamento:

  1. Filtre e agrupe cedo, antes de passos que dependem da linguagem M pura.
  2. Evite colunas personalizadas complexas antes do Group By, elas costumam quebrar a dobra.
  3. Prefira as agregações padrão, que traduzem bem para SQL, em vez de lógicas exóticas de subtabela.
  4. Cheque a consulta nativa depois do agrupamento para confirmar que a dobra chegou até lá.

Quando a fonte é arquivo, como Excel ou CSV, não existe folding e o agrupamento roda sempre no motor local. Se o seu cenário envolve fontes pesadas e pipelines robustos, o trabalho de engenharia de dados é justamente garantir que as transformações certas aconteçam no lugar certo.

Perguntas frequentes

Qual a diferença entre Contagem de Linhas e Contagem de Valores Distintos no Group By? A Contagem de Linhas devolve quantas linhas existem no grupo, incluindo repetições, e usa Table.RowCount. A Contagem de Valores Distintos conta apenas valores únicos de uma coluna, com List.Count(List.Distinct(...)). Para saber quantos pedidos um cliente fez, use linhas. Para saber em quantas cidades diferentes ele comprou, use valores distintos.

O Group By do Power Query dá para desfazer depois? A operação em si é só um passo na consulta, então você pode remover o passo e voltar ao estado anterior enquanto estiver editando. O que não volta é o dado descartado depois que a consulta agregada já foi carregada e a origem detalhada não é mais importada. Por isso a decisão de agregar na consulta precisa considerar o que você pode precisar no futuro.

Como agrupar mantendo todas as colunas originais? Use o agrupamento avançado com a operação Todas as Linhas para guardar a subtabela de cada grupo numa coluna do tipo tabela, e depois expanda as colunas que quiser. Outra opção é fazer o agrupamento numa consulta separada e mesclar o resultado de volta na tabela original por uma chave comum, o que mantém o detalhe intacto.

Agregar no Power Query é mais rápido que agregar em DAX? Depende do cenário. Agregar no Power Query reduz o volume no modelo e, com folding, o trabalho pesado fica no banco. O DAX agrega na hora da consulta, com muita flexibilidade, mas sobre a tabela inteira. Para bases enormes e cortes fixos, pré-agregar ajuda. Para análise flexível com drill-down, o grão fino em DAX quase sempre é a escolha certa.

Por que minha média no Group By saiu diferente do esperado? Quase sempre é por causa de valores nulos. List.Average ignora nulos, então a média é calculada só sobre as linhas com valor. Se o negócio espera que os nulos contem como zero, substitua os nulos por zero num passo anterior ao agrupamento. Vale checar também se há duplicidade na base, que infla contagens e distorce médias.

Dá para usar o Group By em qualquer fonte de dados? Sim, o Table.Group funciona sobre qualquer tabela dentro do Power Query, independente da origem. A diferença é o desempenho: em bancos relacionais o agrupamento tende a sofrer folding e roda no servidor, enquanto em arquivos como CSV e Excel ele roda na máquina que atualiza. O código M é o mesmo, o que muda é onde o processamento acontece.

Onde isso te leva

O Group By parece simples no clique básico, mas revela bastante profundidade quando você domina o Table.Group na mão, o agrupamento por várias colunas e as saídas múltiplas do modo avançado. A habilidade que mais separa projetos bons de projetos frágeis não é a sintaxe, e sim saber quando agregar cedo e quando preservar o grão para o DAX resolver depois. Acerte essa decisão e o resto flui.

Se a sua base está pesada, os relatórios estão lentos ou você não tem certeza sobre onde agregar cada coisa, a gente ajuda a desenhar o pipeline e o modelo do jeito certo. Conheça nossos serviços de Power BI e fale com a gente para conversar sobre o seu caso.

Quer aplicar isso na sua empresa?

A Fynx implementa BI, Power BI e Power Platform de ponta a ponta. Conte seu cenário e devolvemos um diagnóstico direto ao ponto.

Falar com um especialista

Vamos transformar seus dados em decisão?

Conte seu cenário. Devolvemos um diagnóstico e uma proposta com faixa de investimento em poucos dias úteis, sem folheto, direto ao ponto.