J'ai un tableau où chaque personne a un dossier pour chaque jour de l'année. J'ai utilisé cette fonction pour obtenir un total cumulé basé sur la colonne du solde quotidien
CALCULATE(
SUM(Leave[Daily Balance]),
FILTER(
ALLEXCEPT(Leave, Leave[Employee Id]),
Leave[Date] <= EARLIER(Leave[Date])
))
mais j'ai besoin du total cumulé pour redémarrer à partir de 1 si Type = Fonctionnement ET le total cumulé de Solde quotidien est inférieur à zéro ET le Type de la ligne précédente n'est pas égal à Fonctionnement. Ci-dessous, une capture d'écran d'Excel. La colonne de fonction requise est ce à quoi je dois accéder.
powerbi
dax
powerbi-desktop
LynseyC
la source
la source
Réponses:
Il s'agit non seulement d'un total cumulé avec une condition, mais également d'une condition imbriquée / en cluster, car la logique doit être appliquée au niveau de l'ID. Pour les grandes tables, M est meilleur que DAX, car il n'utilise pas autant de RAM. (J'ai blogué à ce sujet ici: Lien vers Blogpost
La fonction suivante adapte cette logique au cas actuel et doit être appliquée au niveau de l'ID: (Les noms de colonnes requis sont: "Type", "Indemnité journalière", "Ajustements")
(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
la source
Aperçu
Il est difficile de demander à PowerBI de le faire, donc une approche bien rangée peut être difficile à trouver.
Le plus gros problème est que le modèle de données de PowerBI ne prend pas en charge le concept d'un décompte en cours d'exécution - du moins pas comme nous le faisons dans Excel. Dans Excel, une colonne peut référencer des valeurs qui se produisent dans la `` ligne précédente '' de cette même colonne, puis être ajustée par certains `` changements quotidiens '' répertoriés dans une autre colonne.
PowerBI ne peut imiter cela qu'en additionnant toutes les modifications quotidiennes sur un sous-ensemble de lignes. Nous prenons la valeur de date dans notre ligne actuelle et créons un tableau filtré où toutes les dates sont inférieures à la date de cette ligne actuelle, puis résumons toutes les modifications quotidiennes de ce sous-ensemble. Cela peut sembler être une différence subtile, mais elle est assez significative:
Cela signifie qu'il n'y a aucun moyen de «remplacer» notre total cumulé. Le seul calcul en cours se produit sur la colonne contenant les modifications quotidiennes - la colonne contenant le «total cumulé» n'est qu'un résultat - elle n'est jamais utilisée dans le calcul d'une ligne ultérieure.
Nous devons abandonner le concept de «réinitialisation» et imaginer à la place de créer une colonne contenant une valeur «d'ajustement». Notre ajustement sera une valeur qui peut être incluse de sorte que lorsque les conditions décrites sont remplies, le total des soldes et ajustements quotidiens sera égal à 1.
Si nous regardons le calcul calculé donné par OP, nous voyons que la valeur de notre total cumulé un jour «non ouvrable» juste avant un jour «ouvrable» nous donne le montant nécessaire qui, s'il était inversé, serait égal à zéro et faire augmenter le total cumulé de chaque jour ouvrable suivant. C'est notre comportement souhaité (avec un problème qui sera décrit plus loin).
Résultat
Il permet de connaître la différence entre les contextes de ligne et de filtre et comment EARLIER fonctionne pour suivre ce calcul. Dans ce scénario, vous pouvez penser à «EARLIER» comme signifiant «cette référence pointe vers la valeur de la ligne actuelle» et sinon une référence pointe vers la table entière renvoyée par «ALLEXCEPT (Leave, Leave [Id])». façon, nous trouvons les endroits où la ligne actuelle a le type "Working" et la ligne de la veille a un autre type.
Ce calcul imite un type d'opération de «remplissage vers le bas». Il indique: «Lorsque vous examinez toutes les lignes dont la date est antérieure à la date sur CETTE ligne, renvoyez la plus grande valeur dans« Date la plus récente avant le travail ».
Maintenant que chaque ligne a un champ expliquant où aller pour trouver le solde quotidien à utiliser comme ajustement, nous pouvons simplement le rechercher dans le tableau.
Et enfin, nous appliquons l'ajustement à notre total cumulé pour le résultat final.
Le problème
Cette approche ne tient pas compte du fait que le décompte ne doit pas être réinitialisé à moins que le solde quotidien en cours soit inférieur à zéro. J'ai déjà eu tort, mais je dirais que cela ne peut pas être accompli uniquement dans DAX car cela crée une dépendance circulaire. Essentiellement, vous faites une exigence: utilisez la valeur agrégée pour déterminer ce qui doit être inclus dans l'agrégation.
Voilà pour autant que je puisse vous amener. J'espère que cela aide.
la source
J'espère que la prochaine fois que vous collerez un csv ou un code qui génère des exemples de données au lieu d'une image. :)
Permettez-moi de vous suggérer de faire vos calculs dans PowerQuery à la place. J'ai essayé de diviser le code en quelques étapes pour améliorer la lisibilité. Cela peut sembler un peu plus complexe, mais fonctionne bien. Il vous suffit de le coller dans l'éditeur avancé, puis de remplacer la source par vos données source. Bonne chance!
la source
Je pense que je l'ai!
Voici le résultat, en s'appuyant sur la solution que j'ai publiée plus tôt: (Les données ont été modifiées pour montrer plus de comportements et de cas d'utilisation "travail / pas de travail")
RÉSULTAT
DÉTAILS
(1) Supprimez les colonnes "Solde quotidien ajusté" et "Ajustement du solde quotidien". Nous obtiendrons le même résultat avec un pas de moins en un instant.
(2) Créez la colonne suivante (RDB = "Running Daily Balance") ...
Après avoir créé la «date la plus récente avant la fin des travaux», nous avons en fait la pièce nécessaire pour effectuer notre «réinitialisation» qui, selon moi, était impossible auparavant. En filtrant sur ce champ, nous avons la possibilité de démarrer chaque tranche à '1'
(3) Nous avons toujours le même problème, nous ne pouvons pas regarder le résultat dans notre colonne et l'utiliser pour décider quoi faire plus tard dans cette même colonne. Mais nous POUVONS construire une nouvelle colonne d'ajustement qui contiendra cette information! Et nous avons déjà une référence à la «date la plus récente avant le travail» - c'est le dernier jour du groupe précédent ... la ligne avec les informations dont nous avons besoin!
Nous examinons donc le dernier jour de chaque groupe précédent et si la somme totale de ces ajustements a une valeur positive, nous l'appliquons et si elle est négative, nous la laissons à la place. De plus, si les premiers jours de notre personne sont des jours chômés, nous ne voulons pas du tout ce bit négatif initial dans notre ajustement afin qu'il soit également filtré.
(4) Cette dernière étape amènera l'ajustement dans le résultat final. Résumez les deux nouvelles colonnes et nous devrions enfin avoir notre solde journalier ajusté. Voila!
Nous avons construit beaucoup de colonnes supplémentaires en cours de route vers ce résultat, ce qui n'est généralement pas mon truc préféré. Mais c'était difficile.
la source
Cela a pris un certain temps, mais j'ai pu trouver une solution de contournement. En supposant que la valeur du solde pour les blancs est toujours -1 et que la valeur est 1 pour "Travail" et que les données sont disponibles pour toutes les dates sans écart, quelque chose comme le calcul ci-dessous pourrait fonctionner:
Gardez à l'esprit que ce n'est peut-être pas un produit fini car j'ai travaillé avec un petit échantillon, mais cela devrait vous aider à démarrer. J'espère que cela t'aides.
la source
Le calcul est un peu long, mais il semble fonctionner dans les exemples de données que j'utilise. Essayez ceci:
J'ai utilisé un tas de variables ici. Vous pourrez peut-être trouver une version plus courte. Fondamentalement, l'idée est de trouver la première occurrence précédente de "Working" pour trouver d'où commencer le calcul. Ceci est calculé dans la variable "Prev_Blank2". Une fois que nous connaissons le point de départ (il commence par 1 ici), nous pouvons simplement compter le nombre de jours avec "Working" ou blank () entre Prev_Blank2 et la date de l'enregistrement en cours. En utilisant ces jours, nous pouvons retourner la valeur finale pour le total cumulé.
Espérons que cela fera l'affaire;)
la source