Tengo una mesa donde cada persona tiene un registro para cada día del año. Utilicé esta función para lograr un total acumulado basado en la columna de saldo diario
CALCULATE(
SUM(Leave[Daily Balance]),
FILTER(
ALLEXCEPT(Leave, Leave[Employee Id]),
Leave[Date] <= EARLIER(Leave[Date])
))
pero necesito el total acumulado para reiniciar desde 1 si Tipo = Funcionando Y el total acumulado de Saldo diario es menor que cero Y el Tipo de la fila anterior no es igual a Funcionando. A continuación se muestra una captura de pantalla de Excel. La columna de función requerida es a lo que necesito llegar.
powerbi
dax
powerbi-desktop
LynseyC
fuente
fuente
Respuestas:
Este no es solo un total acumulado con una condición, sino también uno anidado / agrupado, ya que la lógica debe aplicarse en el nivel de ID. Para tablas grandes, M es mejor que DAX, ya que no usa tanta RAM. (He blogueado sobre eso aquí: Enlace a Blogpost
La siguiente función adapta esa lógica al caso actual y debe aplicarse en el nivel de ID: (Los nombres de columna obligatorios son: "Tipo", "Cantidad diaria", "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
fuente
Visión general
Es un desafío pedirle a PowerBI que haga, por lo que un enfoque ordenado puede ser difícil de encontrar.
El mayor problema es que el modelo de datos de PowerBI no admite el concepto de una cuenta corriente, al menos no de la forma en que lo hacemos en Excel. En Excel, una columna puede hacer referencia a valores que ocurren en la 'fila anterior' de esa misma columna y luego ser ajustados por algún 'cambio diario' que aparece en una columna diferente.
PowerBI solo puede imitar esto sumando todos los cambios diarios en algún subconjunto de filas. Tomamos el valor de la fecha en nuestra fila actual y creamos una tabla filtrada donde todas las fechas son menores que la fecha de esta fila actual, y luego resumimos todos los cambios diarios de ese subconjunto. Esto puede parecer una sutil diferencia, pero es bastante significativo:
Esto significa que no hay forma de 'anular' nuestro total acumulado. La única matemática que se está haciendo está sucediendo en la columna que contiene cambios diarios: la columna que contiene 'total acumulado' es solo un resultado, nunca se usa en el cálculo de una fila posterior.
Debemos abandonar el concepto de 'reinicio' y, en su lugar, imaginar hacer una columna que contenga un valor de 'ajuste'. Nuestro ajuste será un valor que se puede incluir para que cuando se cumplan las condiciones descritas, el total de los saldos diarios y los ajustes sumen 1.
Si observamos la ejecución calculada dada por OP, vemos que el valor de nuestro total acumulado en un día 'no laborable' justo antes de un día 'laborable' nos da esa cantidad necesaria que, si se invierte, sumaría cero y hacer que el total acumulado en cada día hábil siguiente aumente en uno. Este es nuestro comportamiento deseado (con un problema que se describirá más adelante).
Resultado
Ayuda a conocer la diferencia entre los contextos de fila y filtro y cómo opera EARLIER para seguir este cálculo. En este escenario, puede pensar que "ANTERIOR" significa 'esta referencia apunta al valor en la fila actual "y, de lo contrario, una referencia apunta a toda la tabla devuelta por" ALLEXCEPT (Leave, Leave [Id]) ". De esta manera, encontramos los lugares donde la fila actual tiene el tipo "Working" y la fila del día anterior tiene otro tipo.
Este cálculo imita un tipo de operación de "relleno". Dice: "Al mirar todas las filas cuya fecha es anterior a la fecha en ESTA fila, devuelve el valor más grande en 'Fecha más reciente antes del trabajo".
Ahora que cada fila tiene un campo que explica a dónde ir para encontrar el saldo diario para usar como nuestro ajuste, podemos ir a buscarlo desde la tabla.
Y finalmente aplicamos el ajuste a nuestro total acumulado para el resultado final.
La cuestión
Este enfoque no aborda que el recuento no se debe restablecer a menos que el saldo diario en ejecución sea inferior a cero. Se me demostró que estaba equivocado antes, pero diría que esto no se puede lograr solo en DAX porque crea una dependencia circular. Esencialmente, usted hace un requisito: use el valor agregado para determinar qué debe incluirse en la agregación.
Así que hasta aquí puedo llevarte. Espero eso ayude.
fuente
Espero que la próxima vez pegue un csv o código que genere datos de muestra en lugar de una imagen. :)
Déjame sugerirte que hagas tus cálculos en PowerQuery. Traté de dividir el código por unos pocos pasos para mejorar la legibilidad. Esto puede parecer un poco más complejo, pero funciona bien. Simplemente péguelo en el editor avanzado y luego reemplace la fuente con sus datos fuente. ¡La mejor de las suertes!
fuente
Creo que lo tengo!
Aquí está el resultado, basándose en la solución que publiqué anteriormente: (Los datos se han modificado para mostrar más comportamientos de "trabajo / no trabajo" y casos de uso)
RESULTADO
DETALLES
(1) Suelte las columnas "Saldo diario ajustado ajustado" y "Ajuste de saldo diario". Obtendremos el mismo resultado con un paso menos en un momento.
(2) Cree la siguiente columna (RDB = "ejecución del saldo diario") ...
Después de haber creado la "Fecha más reciente antes de completar el trabajo", en realidad tenemos la pieza necesaria para hacer nuestro 'reinicio' que, según yo, era imposible antes. Al filtrar en este campo, tenemos la oportunidad de comenzar cada segmento en '1'
(3) Aún tenemos el mismo problema, no podemos ver el resultado en nuestra columna y usarlo para decidir qué hacer más adelante en esa misma columna. ¡Pero PODEMOS construir una nueva columna de ajuste que contendrá esa información! Y ya tenemos una referencia a 'Fecha más reciente antes del trabajo': ese es el último día del grupo anterior ... ¡la fila con la información que necesitamos!
Así que miramos el último día en Cada grupo anterior y si la suma total de esos ajustes tiene un valor positivo, lo aplicamos y, si es negativo, lo dejamos en su lugar. Además, si los primeros días de nuestra persona son días no laborables, no queremos ese bit negativo inicial en nuestro ajuste para que también se filtre.
(4) Este último paso traerá el ajuste al resultado final. Resuma las dos nuevas columnas y finalmente deberíamos tener nuestro Saldo diario ajustado ajustado. Voila!
Creamos muchas columnas adicionales en el camino hacia este resultado, que generalmente no es lo que más me gusta hacer. Pero, esto fue complicado.
fuente
Tomó un tiempo, pero pude encontrar una solución alternativa. Suponiendo que el valor del saldo para espacios en blanco es siempre -1 y el valor es 1 para "Trabajo" y que los datos están disponibles para todas las fechas sin espacio, algo como el siguiente cálculo podría funcionar:
Tenga en cuenta que esto podría no ser un producto terminado ya que trabajé con una pequeña muestra, pero esto debería ayudarlo a comenzar. Espero que esto ayude.
fuente
El cálculo es un poco largo, pero parece estar funcionando en los datos de muestra que estoy usando. Prueba esto:
He usado un montón de variables aquí. Tal vez puedas llegar a una versión más corta. Básicamente, la idea es encontrar la primera aparición anterior de "Trabajo" para encontrar desde dónde comenzar el cálculo. Esto se calcula en la variable "Prev_Blank2". Una vez que conocemos el punto de partida (comienza con 1 aquí), entonces podemos simplemente contar la cantidad de días con "Working" o blank () entre Prev_Blank2 y la fecha del registro actual. Con estos días, podemos devolver el valor final para el total acumulado.
Esperemos que esto haga el truco;)
fuente