Eu tenho uma mesa onde cada pessoa tem um recorde para todos os dias do ano. Eu usei essa função para obter um total corrente com base na coluna de saldo diário
CALCULATE(
SUM(Leave[Daily Balance]),
FILTER(
ALLEXCEPT(Leave, Leave[Employee Id]),
Leave[Date] <= EARLIER(Leave[Date])
))
mas preciso que o total em execução seja reiniciado a partir de 1 se Tipo = Trabalhando E o total em execução do Saldo Diário for menor que zero E o Tipo da linha anterior não for igual a Trabalhar. Abaixo está uma captura de tela do Excel. A coluna de função necessária é o que eu preciso acessar.
powerbi
dax
powerbi-desktop
LynseyC
fonte
fonte
Respostas:
Este não é apenas um total em execução com uma condição, mas também um agrupado / aninhado, pois a lógica deve ser aplicada no nível do ID. Para tabelas grandes, o M é melhor do que o DAX, pois não usa tanta RAM. (Eu escrevi sobre isso aqui: Link para o Blogpost
A função a seguir adapta essa lógica ao caso atual e deve ser aplicada no nível do ID: (os nomes das colunas necessárias são: "Tipo", "Dose diária", "Ajustes")
(MyTable as table) => let SelectJustWhatsNeeded = Table.SelectColumns(MyTable,{"Type", "Daily Allowance", "Adjustments"}), ReplaceNulls = Table.ReplaceValue(SelectJustWhatsNeeded,null,0,Replacer.ReplaceValue,{"Adjustments"}), #"Merged Columns" = Table.CombineColumns(ReplaceNulls,{"Daily Allowance", "Adjustments"}, List.Sum,"Amount"), TransformToList = List.Buffer(Table.ToRecords(#"Merged Columns")), ConditionalRunningTotal = List.Skip(List.Generate( () => [Type = TransformToList{0}[Type], Result = 0, Counter = 0], each [Counter] <= List.Count(TransformToList), each [ Result = if TransformToList{[Counter]}[Type] = "working" and [Result] < 0 and [Type] <> "working" then TransformToList{[Counter]}[Amount] else TransformToList{[Counter]}[Amount] + [Result] , Type = TransformToList{[Counter]}[Type], Counter = [Counter] + 1 ], each [Result] )), Custom1 = Table.FromColumns( Table.ToColumns(MyTable) & {ConditionalRunningTotal}, Table.ColumnNames(MyTable) & {"Result"} ) in Custom1
fonte
Visão geral
É algo difícil de pedir ao PowerBI, portanto, pode ser difícil encontrar uma abordagem organizada.
O maior problema é que o modelo de dados do PowerBI não suporta o conceito de contagem em execução - pelo menos não da maneira que fazemos no Excel. No Excel, uma coluna pode fazer referência a valores que ocorrem na 'linha anterior' da mesma coluna e, em seguida, ser ajustada por algumas 'alterações diárias' listadas em uma coluna diferente.
O PowerBI só pode imitar isso adicionando todas as alterações diárias em algum subconjunto de linhas. Pegamos o valor da data em nossa linha atual e criamos uma tabela filtrada em que todas as datas são inferiores à data dessa linha atual e, em seguida, resumimos todas as alterações diárias desse subconjunto. Isso pode parecer uma diferença sutil, mas é bastante significativa:
Isso significa que não há como "substituir" nosso total de rodadas. A única matemática que está sendo feita está acontecendo na coluna que contém alterações diárias - a coluna que contém 'total em execução' é apenas um resultado - nunca é usada no cálculo de nenhuma linha subsequente.
Devemos abandonar o conceito de 'reset' e, em vez disso, imaginar fazer uma coluna que contenha um valor de 'ajuste'. Nosso ajuste será um valor que pode ser incluído para que, quando as condições descritas forem atendidas, o total de saldos e ajustes diários totalize 1.
Se observarmos a execução calculada fornecida pelo OP, veremos que o valor de nossa execução total em um dia 'não útil', imediatamente antes de um dia 'útil', nos fornece a quantidade necessária que, se revertida, somará zero e aumentar o número de rodadas em cada dia útil seguinte em um. Este é o nosso comportamento desejado (com um problema a ser descrito posteriormente).
Resultado
Ajuda a saber a diferença entre os contextos de linha e filtro e como o EARLIER opera para seguir esse cálculo. Nesse cenário, você pode pensar em "EARLIER" como significando 'esta referência aponta para o valor na linha atual "e, caso contrário, uma referência aponta para toda a tabela retornada por" ALLEXCEPT (Deixar, Deixar [Id]). " Dessa forma, encontramos os locais em que a linha atual tem o tipo "Working" e a linha do dia anterior tem outro tipo.
Este cálculo imita um tipo de operação 'preenchimento'. Ele diz: "Ao examinar todas as linhas cuja data é anterior à data nesta linha, retorne o maior valor em 'Data mais recente antes do trabalho".
Agora que todas as linhas têm um campo explicando para onde encontrar o saldo diário a ser usado como ajuste, podemos apenas procurar na tabela.
E, finalmente, aplicamos o ajuste ao nosso total corrente para o resultado final.
O problema
Essa abordagem falha ao abordar que a contagem não deve ser redefinida, a menos que o saldo diário em execução esteja abaixo de zero. Eu já me provei errado antes, mas diria que isso não pode ser realizado apenas no DAX, porque cria uma dependência circular. Essencialmente, você faz um requisito: use o valor agregado para determinar o que deve ser incluído na agregação.
Então é isso que eu posso te trazer. Espero que ajude.
fonte
Espero que da próxima vez que você cole um csv ou código que gere dados de amostra em vez de imagem. :)
Deixe-me sugerir que você faça seus cálculos no PowerQuery. Tentei dividir o código em algumas etapas para melhorar a legibilidade. Isso pode parecer um pouco mais complexo, mas funciona bem. Basta colá-lo no editor avançado e substituir a fonte pelos dados de origem. Boa sorte!
fonte
Eu acho que tenho!
Aqui está o resultado, baseado na solução que eu postei anteriormente: (Os dados foram modificados para mostrar mais comportamentos e casos de uso "sem trabalho"
RESULTADO
DETALHES
(1) Solte as colunas "Saldo diário em execução ajustado" e "Ajuste do saldo diário". Obteremos o mesmo resultado com apenas um passo em apenas um momento.
(2) Crie a seguinte coluna (RDB = "executando o saldo diário") ...
Depois de criar a "Data mais recente antes do término do trabalho", na verdade temos a peça necessária para fazer nossa 'redefinição' que eu alegava ser impossível antes. Ao filtrar esse campo, temos a oportunidade de iniciar cada fatia no '1'
(3) Ainda temos o mesmo problema, não podemos olhar para o resultado em nossa coluna e usá-lo para decidir o que fazer posteriormente nessa mesma coluna. Mas PODEMOS construir uma nova coluna de ajuste que conterá essa informação! E já temos uma referência a 'Data mais recente antes do trabalho' - esse é o último dia do grupo anterior ... a linha com as informações de que precisamos!
Então, olhamos para o último dia em Each grupo anterior e, se a soma total desses ajustes tiver um valor positivo, aplicamos e, se for negativo, deixamos em paz. Além disso, se os primeiros dias de nossa pessoa são dias não úteis, não queremos esse bit negativo inicial em nosso ajuste, para que ele também seja filtrado.
(4) Este último passo trará o ajuste para o resultado final. Resuma as duas novas colunas e finalmente teremos nosso saldo diário de execução ajustado. Voila!
Construímos muitas colunas extras ao longo do caminho para esse resultado, o que geralmente não é a minha coisa favorita a fazer. Mas, isso foi complicado.
fonte
Demorou um pouco, mas consegui encontrar uma solução alternativa. Supondo que o valor do saldo para espaços em branco seja sempre -1 e o valor seja 1 para "Trabalhando" e que os dados estejam disponíveis para todas as datas sem intervalo, algo como o cálculo abaixo poderia funcionar:
Lembre-se de que esse pode não ser um produto final, pois trabalhei com uma pequena amostra, mas isso deve ajudá-lo a começar. Espero que isto ajude.
fonte
O cálculo é um pouco demorado, mas parece estar funcionando nos dados de amostra que estou usando. Faça uma tentativa:
Eu usei um monte de variáveis aqui. Você talvez consiga criar uma versão mais curta. Basicamente, a idéia é encontrar a primeira ocorrência anterior de "Trabalhando" para descobrir de onde iniciar o cálculo. Isso é calculado na variável "Prev_Blank2". Depois de conhecermos o ponto de partida (começa com 1 aqui), podemos simplesmente contar o número de dias com "Working" ou em branco () entre Prev_Blank2 e a data do registro atual. Usando esses dias, podemos retornar o valor final para a execução total.
Espero que isso faça o truque;)
fonte