Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Learn from the best! Meet the four finalists headed to the FINALS of the Power BI Dataviz World Championships! Register now

Reply
Goodkat
Helper II
Helper II

Calculate a value based on its previous value in the same column

Dear Power Query forum,


I am stuck with a logically simple and in an excel spreadsheet fairly easy to realize problem; but in PQ it exceeds my current capabilities. Also search in the internet, including this forum and youtube, did not provide a tangible result.
I have a list of year & month combinations which I want to enrich with a decreasing value, based on the previous row value multiplied by a rate of decrease. In the spreadsheet the column [DeclineExcel] shows my aspired outcome with excel formulas. But in the particular case I want to use this, I cannot do it in excel. And also as thinking about this in PQ intrigued me, I want to learn how to achieve that in PQ.
So I added an index column and tried to reference with the previous step and the current index -1. But it failed and I also sense that this approach is too simple to work.

 

https://c.gmx.net/@324888734501700174/fqDf8Y0Tnd_LIMscLcrNkQ

 

Does the forum have any idea or an example which PQ statements can solve such task?

 

Thank you!

 

Best regards, Andreas

1 ACCEPTED SOLUTION
MarkLaf
Super User
Super User

This just goes through ValueStart and Rate and applies the same formula as in your Excel.

 

Sample

Year Month ValueStart Rate
2025 4 14 0.015
2025 5 null 0.015
2025 6 null 0.015
2025 7 null 0.015
2025 8 null 0.015
2025 9 null 0.015
2025 10 null 0.015
2025 11 null 0.015
2025 12 null 0.015
2026 1 null 0.015
2026 2 null 0.015
2026 3 null 0.015
2026 4 null 0.015
2026 5 null 0.015
2026 6 null 0.015
2026 7 null 0.015
2026 8 null 0.015
2025 2 28 0.023
2025 3 null 0.023
2025 4 null 0.023
2025 5 null 0.023
2025 6 null 0.023
2025 7 null 0.023
2025 8 null 0.023
2025 9 null 0.023
2025 10 null 0.023
2025 11 null 0.023
2025 12 null 0.023
2026 1 null 0.023
2026 2 null 0.023
2026 3 null 0.023
2026 4 null 0.023

 

M (advanced editor)

let
    Source = Sample,
    ValueStarts = List.Buffer( Source[ValueStart] ),
    Rates = List.Buffer( Source[Rate] ),
    GenDecline = List.Generate(
        ()=>[i=0,v=ValueStarts{i}], each [i] < Table.RowCount(Source), 
        each [
            i = [i] + 1, 
            v = if ValueStarts{i} is null then [v]*(1-Rates{i}) else ValueStarts{i}
        ],
        each [v]
    ),
    CombineColumns = Table.FromColumns( 
        Table.ToColumns(Source) & {GenDecline}, 
        // dynamically adds new column name and type to Source
        // with given sample, equivalent of: 
        // type table [Year=Int64.Type,Month=Int64.Type,ValueStart=number,Rate=number,Decline=number]
        type table Type.ForRecord( 
            Type.RecordFields( Type.TableRow( Value.Type( Source ) ) ) 
            & [Decline=[Type=type number,Optional=false]], 
            false 
        ) 
    )
in
    CombineColumns

 

Output

MarkLaf_0-1770250808825.png

 

 

View solution in original post

4 REPLIES 4
MarkLaf
Super User
Super User

This just goes through ValueStart and Rate and applies the same formula as in your Excel.

 

Sample

Year Month ValueStart Rate
2025 4 14 0.015
2025 5 null 0.015
2025 6 null 0.015
2025 7 null 0.015
2025 8 null 0.015
2025 9 null 0.015
2025 10 null 0.015
2025 11 null 0.015
2025 12 null 0.015
2026 1 null 0.015
2026 2 null 0.015
2026 3 null 0.015
2026 4 null 0.015
2026 5 null 0.015
2026 6 null 0.015
2026 7 null 0.015
2026 8 null 0.015
2025 2 28 0.023
2025 3 null 0.023
2025 4 null 0.023
2025 5 null 0.023
2025 6 null 0.023
2025 7 null 0.023
2025 8 null 0.023
2025 9 null 0.023
2025 10 null 0.023
2025 11 null 0.023
2025 12 null 0.023
2026 1 null 0.023
2026 2 null 0.023
2026 3 null 0.023
2026 4 null 0.023

 

M (advanced editor)

let
    Source = Sample,
    ValueStarts = List.Buffer( Source[ValueStart] ),
    Rates = List.Buffer( Source[Rate] ),
    GenDecline = List.Generate(
        ()=>[i=0,v=ValueStarts{i}], each [i] < Table.RowCount(Source), 
        each [
            i = [i] + 1, 
            v = if ValueStarts{i} is null then [v]*(1-Rates{i}) else ValueStarts{i}
        ],
        each [v]
    ),
    CombineColumns = Table.FromColumns( 
        Table.ToColumns(Source) & {GenDecline}, 
        // dynamically adds new column name and type to Source
        // with given sample, equivalent of: 
        // type table [Year=Int64.Type,Month=Int64.Type,ValueStart=number,Rate=number,Decline=number]
        type table Type.ForRecord( 
            Type.RecordFields( Type.TableRow( Value.Type( Source ) ) ) 
            & [Decline=[Type=type number,Optional=false]], 
            false 
        ) 
    )
in
    CombineColumns

 

Output

MarkLaf_0-1770250808825.png

 

 

Dear MarkLaf,


thank you so much for providing your solution! List.Generate I did not have on my radar. Your code works as expected and directed me towards several aspects I must now further explore with the knowledge materials out there.

 

Best regards, Andreas

jgeddes
Super User
Super User

There are probably more efficient ways to do this. But this should work for you. It relies on grouping the table into sections and generating an output list for each section. A nested zero based index is then used to extract the desired output from the index position of the list.

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("fdFBDoAgDETRu7AmhlaoeBbj/a+hjYmK6XcBizeQNNNtS1q0pZzqecSvMhVpac934idyA1/AO/gKLoUCoUCDwMeMPrjT+xm8gkcVGVRkUJH9VORzar8Snd/JM+noFbyBG/gC3sFX8NcyP4FQoEEwLnN0eh9VNC7TfT8A", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Year = _t, Month = _t, ValueStart = _t, Rate = _t]),
    #"Changed Type" = 
    Table.TransformColumnTypes(
        Source,
        {
            {"Year", Int64.Type}, {"Month", Int64.Type}, {"ValueStart", Int64.Type}, {"Rate", type number}
        }
    ),
    //this uses the ValueStart column to group the the table into sections that can be indexed and can have the list generate fuction applied.
    //it would be more stable if a more reliable grouping column was used.
    #"Filled Down" = 
    Table.FillDown(
        #"Changed Type",
        {"ValueStart"}
    ),
    //group the table by ValueStart and Rate, getting a nested table row count and all rows in the table
    #"Grouped Rows" = 
    Table.Group(
        #"Filled Down", 
        {"ValueStart", "Rate"}, 
        {
            {"Count", each Table.RowCount(_), Int64.Type}, 
            {"AllRows", each _, type table [Year=nullable number, Month=nullable number, ValueStart=nullable number, Rate=nullable number]}
        }
    ),
    //use the List.Generate function to create a list of outputs 
    Custom2 = 
    Table.AddColumn(
        #"Grouped Rows", 
        "list", 
        each 
        List.Generate(
            ()=> [
                    x=[ValueStart],             //initial x value is the ValueStart value for the row
                    y=[Rate],                   //y is always the Rate for the row
                    z=[Count]                   //z is the number of rows in the nested table, i.e., the number of output rows we need
                ], 
                each [z] > 0,                   //iterates as long as z is > 0 
                each [
                        x= [x] - ([x]*[y]),     //for every iteration, x is set to the previous value of x minus the previous value of x times the rate
                        y=[y],                  //y never changes
                        z = [z]-1               //z is decreased by one for every iteration
                    ], 
                each [x]                        //return the value of x to the list
        ), 
        type list
    ),
    //add an index column to the nested AllRows table. IMPORTANT that this starts at 0 for list indexing reasons.
    Custom1 = 
    Table.TransformColumns(
        Custom2, 
        {
            {"AllRows", each Table.AddIndexColumn(_, "Index", 0, 1, Int64.Type), type table [Year=nullable number, Month=nullable number, Index=nullable number]}
        }
    ),
    //expand the needed columns from the nested table to new rows
    #"Expanded AllRows" = 
    Table.ExpandTableColumn(
        Custom1, 
        "AllRows", 
        {"Year", "Month", "Index"}, 
        {"Year", "Month", "Index"}
    ),
    //add a column that displays the value from the list at the current row's index position. 
    Custom3 = 
    Table.AddColumn(
        #"Expanded AllRows", 
        "Output", 
        each [list]{[Index]}, 
        type number
    ),
    //sort the needed columns
    Custom4 = 
    Table.SelectColumns(
        Custom3, 
        {"Year", "Month", "ValueStart", "Rate", "Output"}
    )
in
    Custom4

jgeddes_0-1770241843285.png

 





Did I answer your question? Mark my post as a solution!

Proud to be a Super User!





Dear jgeddes,

thank you for taking the time and come up with a solution. I have implmented the code in my sample file and it works! For efficiency I think I will go for now with the other solution in this thread, but as in your code some other commands are featured I will also keep it to learn more about these commands.

 

Best regards, Andreas

Helpful resources

Announcements
Join our Fabric User Panel

Join our Fabric User Panel

Share feedback directly with Fabric product managers, participate in targeted research studies and influence the Fabric roadmap.

February Power BI Update Carousel

Power BI Monthly Update - February 2026

Check out the February 2026 Power BI update to learn about new features.

FabCon Atlanta 2026 carousel

FabCon Atlanta 2026

Join us at FabCon Atlanta, March 16-20, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.

Top Solution Authors