Loop com Power Query

Em determinados contextos de manipulação de dados, a necessidade de empregar estruturas de loop se faz presente para processar um valor específico ou extrair informações, especialmente quando há relações em múltiplos níveis e a quantidade de níveis não é predefinida. Em ambientes de bancos de dados como SQL Server, Oracle, PostgreSQL, ou outros semelhantes, recorremos a comandos como “while” ou “for” para realizar tais operações. No entanto, quando estamos trabalhando com o Power Query, a abordagem para implementar esses procedimentos difere.

Como podemos realizar essas operações no Power Query?

Vejamos o seguinte exemplo:

Observando a tabela a seguir temos um controle de OS relacionando a Abertura da OS, Complementos dela e o Fechamento.

TipoOSDataOS OrigemValor
Abertura1564001/01/2024    75,00
Complemento1569801/01/202415640 
Complemento1597405/01/202415698 
Complemento1601006/01/202415974 
Complemento1613209/01/202416010 
Fechamento1646412/01/202416132   25,00
Fechamento1678815/01/202416132   25,00
Fechamento1680016/01/202415698   25,00

Suponhamos que precisamos filtra as Aberturas e adicionar a elas o Número do Fechamento, Data e Valor.

Como poderíamos realizar isso?

A lógica é a seguinte

1º Verificar se a OS está atrelada a algum registro.

2º Separar destes os tipos Complemento e Fechamento

3º Se o tipo for igual a Complemento, buscar um fechamento se não retornar o resultado.

Com o conceito definido podemos construir nosso código, abaixo temos um exemplo completo para tratar essa situação.(Criamos uma função personalizada para isso, o bloco da função esta em destaque)

let
    
    Etapa1 = /*Leitura dos dados não tratados*/
    Excel.CurrentWorkbook(){[Name="Tabela1"]}[Content],

    /*Função de Loop para encontra os dados do fechamento da OS de Abertura*/
    getFechamento = ( pDB, pRelacao)  => 
            let
                
                Parte1 = /*Verifica se existe alguma OS Relacionada com a OS informada na Função*/
                Table.SelectRows(pDB,each [#"OS Origem"] = Int64.From(pRelacao)),

                Parte2 = /*Filtra os Complementos encontrados*/
                Table.SelectRows(Parte1,each [Tipo] = "Complemento"),
                
                Parte3 = /*Filtra os Fechamentos*/
                Table.SelectRows(Parte1,each [Tipo] = "Fechamento"),

                RetResultado = /*Avalia para rodar a função novamente criando o processo de Loop*/
                if Table.RowCount(Parte2) > 0 /*Verifica se ainda tem registros do tipo Complemento*/
                then /*Se existir executa novamente a função*/
                              Table.Combine({
                    Table.ExpandTableColumn(
                        Table.RemoveColumns(
                            Table.AddColumn( Parte2, "Dados", each @getFechamento(pDB,[OS]), type table)
                                           , {"Tipo", "OS", "Data", "OS Origem", "Valor"})
                                           , "Dados", {"Tipo", "OS", "Data", "OS Origem", "Valor"})
                                           , Parte3 })
                else /* Se não existir retorna o resultado*/
                    Parte3
            in
                RetResultado,

    Etapa2 = /*Filtra os tipos Abertura e chama a Função*/
    Table.ExpandTableColumn(
            Table.AddColumn(
        Table.RemoveColumns(
           Table.SelectRows(Etapa1, each [Tipo] = "Abertura")
                           ,{"OS Origem"})
                           ,"Dados", each getFechamento(Etapa1,[OS]), type table)
                           ,"Dados",{"OS","Data","Valor"},{"OS Fechamento","Data Fechamento","Valor Fechamento"}),

    Etapa3 = /*Define os tipos aos dados*/
    Table.TransformColumnTypes(Etapa2,{{"Tipo", type text}, {"OS", Int64.Type}, {"Data", type date}, {"OS Fechamento", Int64.Type}, {"Data Fechamento", type date},{"Valor", type number}, {"Valor Fechamento", type number} })

in
    Etapa3

O retorno deste código acima será o seguinte:

TipoOSDataValorOS FechamentoData FechamentoValor Fechamento
Abertura1564001/01/2024   75,001646412/01/2024                           25,00
Abertura1564001/01/2024   75,001678815/01/2024                           25,00
Abertura1564001/01/2024   75,001680016/01/2024                           25,00

Ao analisar o segmento da nossa função personalizada, percebemos que a invocamos dentro do próprio corpo da função, é ai que está o pulo do gato para criar um Loop no Power Query. Sempre que há a necessidade de autorreferenciar uma função precisamos anteceder o seu nome com o caractere @. Isso notifica ao compilador que estamos fazendo referência à própria função durante a chamada, estabelecendo assim a lógica essencial para o funcionamento do loop.

/*Função de Loop para encontra os dados do fechamento da OS de Abertura*/
    getFechamento = ( pDB, pRelacao)  => 
            let
                
                Parte1 = /*Verifica se existe alguma OS Relacionada com a OS informada na Função*/
                Table.SelectRows(pDB,each [#"OS Origem"] = Int64.From(pRelacao)),

                Parte2 = /*Filtra os Complementos encontrados*/
                Table.SelectRows(Parte1,each [Tipo] = "Complemento"),
                
                Parte3 = /*Filtra os Fechamentos*/
                Table.SelectRows(Parte1,each [Tipo] = "Fechamento"),

                RetResultado = /*Avalia para rodar a função novamente criando o processo de Loop*/
                if Table.RowCount(Parte2) > 0 /*Verifica se ainda tem registros do tipo Complemento*/
                then /*Se existir executa novamente a função*/
                              Table.Combine({
                    Table.ExpandTableColumn(
                        Table.RemoveColumns(
                            Table.AddColumn( Parte2, "Dados", each @getFechamento(pDB,[OS]), type table)
                                           , {"Tipo", "OS", "Data", "OS Origem", "Valor"})
                                           , "Dados", {"Tipo", "OS", "Data", "OS Origem", "Valor"})
                                           , Parte3 })
                else /* Se não existir retorna o resultado*/
                    Parte3
            in
                RetResultado,

Ao utilizar loops no tratamento de dados com o Power Query ou qualquer outra ferramenta, é importante considerar alguns cuidados para garantir a eficiência e a correta manipulação dos dados.

Evite o uso de loops desnecessários ou excessivamente longos, pois estes impactaram negativamente o desempenho da consulta.

Ao usar loops recursivos, certifique-se de que a condição de parada seja clara e alcançável para que não ocorra um loop infinito e assim travar a consulta.

Depois nos conta ai se te ajudou o se encontrou uma abordagem melhor.

Desejamos que o conteúdo tenha sido útil para o seu aprendizado.
– essa foi mais uma dica do Ornit 😉.


Comentários

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *