Forum Discussion

Wesley0107's avatar
Wesley0107
Icon for Resolver I rankResolver I
1 year ago

Calculate with data in previous rows fails when year changes

Advanced Editor:

    // Define the lower bound
    Limit = 0,

    // Obtain Current Index and ID
    CurrentIndex = [Index1],
    CurrentEmployeeID = [ID],

    // Obtain the change
    CurrentChange = [Change],
    
    // Filter the rows for the same ID but with a lower index
    PreviousRows = Table.SelectRows(#"XXX", each [ID] = CurrentID and [Index1] < CurrentIndex),

    // Calculate the cumulative sum
    CumulativeSum = List.Accumulate(
    PreviousRows[Change], 
    0, 
    (state, current) => 
        let
            NewSum = state + current
        in
            if NewSum < Limit then Limit else NewSum
        ),

    // Calculate the total balance including the current change balance
    ChangeDeviation = Change,
    AdjustedTotal = CumulativeSum + ChangeDeviation,
    
    // Check limit
    FinalBalance = if AdjustedTotal < Limit then Limit else AdjustedTotal
in
    FinalBalance),

Hi all,

 

I am currently experiencing the following problem. Please refer to the table below. 

 


As can be seen, it adds up in the ‘Balance’ column with the value from the ‘Change’ column from the previous line. Also, there is a limit in force that ensures that the ‘Balance’ cannot go below 0.

In month 3 of 2024, things suddenly go wrong. I expect 0 + 3.54895104895105 = 3.54895104895105. However, what happens now is 0 + 3.54895104895105 + 3.42657342657343 = 6.97552447552448. That is not the intention.

As you can see, it reverts to the last value from the previous year. Do any of you have any idea how this comes about? Also see my code.

 

Please note that I am not an Power BI/Power Query expert. 

 

Thank you.

 

 

 

 

5 Replies

  • Hi Wesley0107 ,

    If you want your balance to continue across years (so it doesn’t reset every January), you just need to tweak the way you filter previous rows in your calculation.

     

    Here’s what to do in Power Query (M): Instead of filtering by both [Index] and [Year], just use [Index] (and any grouping key you need, like EmployeeID). Here’s a template:

    let
        AddCumulative = Table.AddColumn(PreviousStep, "Balance", (currentRow) =>
            let
                PreviousRows = Table.SelectRows(PreviousStep,
                    (r) =>
                        r[Index] <= currentRow[Index]
                        // Include grouping key here if needed, e.g.:
                        // and r[EmployeeID] = currentRow[EmployeeID]
                ),
                RunningTotal = List.Sum(PreviousRows[Change])
            in
                RunningTotal
        )
    in
        AddCumulative
    

     

    That way, your running total simply keeps going, regardless of the year.

    If you’re using Power BI and prefer DAX, here’s a similar approach:

    Balance = 
    CALCULATE(
        SUM('Table'[Change]),
        FILTER(
            ALL('Table'),
            'Table'[EmployeeID] = EARLIER('Table'[EmployeeID]) &&
            'Table'[Index] <= EARLIER('Table'[Index])
        )
    )
    

     

    Just replace EmployeeID with whatever field(s) you want to group by.


    Make sure your [Index] column is created after sorting your table exactly the way you want the calculation to run—otherwise, the running total can go off track.

    • Wesley0107's avatar
      Wesley0107
      Icon for Resolver I rankResolver I

      Hi Rohit,

       

      Thank you for your reply and for sharing your code.

       

      If I am correct, your code will reset the balance row at each new year? I would, however, like it to just continue regardless of what year it is.

  • Anonymous's avatar
    Anonymous
    Not applicable

    Hi Wesley0107 ,

     

    Here I create a sample to have a test and it should work on myside. You can download my attachment and compare my sample with yours.

    let
     Limit = 0,
    // Obtain Current Index and ID
    CurrentIndex = [Index],
    CurrentEmployeeID = [ID],
    // Obtain the change
    CurrentChange = [Change],
    // Filter the rows for the same ID but with a lower index
    PreviousRows = Table.SelectRows(#"Added Index", each [ID] = CurrentEmployeeID and [Index] < CurrentIndex),
    // Calculate the cumulative sum
    CumulativeSum = List.Accumulate(
        PreviousRows[Change], 
        0, 
        (state, current) => 
            let
                NewSum = state + current
            in
                if NewSum < Limit then Limit else NewSum
            ),
    // Calculate the total balance including the current change balance
    ChangeDeviation = [Change],
    AdjustedTotal = CumulativeSum + ChangeDeviation,
    // Check limit
    FinalBalance = 
    if AdjustedTotal < Limit then Limit else AdjustedTotal
    in
    FinalBalance

    Result is as below.

     

    Best Regards,
    Rico Zhou

     

    If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.

     

    • Wesley0107's avatar
      Wesley0107
      Icon for Resolver I rankResolver I

      Hi Rico,

       

      When I try this myself in a local PBI version - with sample data, it works. But when I am doing this in the 'live version' of our PBI dashboard - with real data, it does not work...

       

      Do you have any idea what causes this? Could it be something with the IDs? Or Index? 

       

      Best regards,

      • Anonymous's avatar
        Anonymous
        Not applicable

        Hi Wesley0107 ,

         

        Is there any different from your local version and the live version?

        On myside, the code works and I think the logic is correct if you only consider the [Index] and [ID] in your filter.

        You could try to publish the local version to Power BI Service and try whether the M code would work.

        If this still couldn't work, I think you may check the data model of your  online version.

         

        Best Regards,
        Rico Zhou

         

        If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.