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

The Power BI Data Visualization World Championships is back! Get ahead of the game and start preparing now! Learn more

Reply
tomekm
Helper III
Helper III

Calculate price evolution: which is the difference in yearly prices for a given project value

Hello,

 

I'm trying to calculate a "price evolution" calculation with a calculated column, so that for each project we calculate the difference between the first period (price 1) and its last period (where a value is available). My table looks like the following, and the last column is the expected outcome: 
- For project a, price 1 - price 2, divided by 2 (since there's only 2 year columns containing a 'price' value for this project), and then divided by price 1 column. Please advise. 

 

projectprice1price2price3price4price erosion (percentage)
a25  -0.75
b345 -0.22
c67930.125

 

 

Thank you.

1 ACCEPTED SOLUTION
danextian
Super User
Super User

Hi @tomekm 

 

Try the following:

Price erosion = 
-- Capture the value from the 'price1' column of the table.
VAR _price1 = tbl[price1]

-- Create a filtered table '_tbl' using SELECTCOLUMNS, assigning indices (1, 2, 3, 4) to prices.
-- The SELECTCOLUMNS function assigns column names ("Index" and "Price") to the two columns.
-- Then, the FILTER function removes any rows where 'Price' is blank.
VAR _tbl =
    FILTER (
        SELECTCOLUMNS (
            {
                ( 1, tbl[price1] ), -- Assign 1 to 'price1'
                ( 2, tbl[price2] ), -- Assign 2 to 'price2'
                ( 3, tbl[price3] ), -- Assign 3 to 'price3'
                ( 4, tbl[price4] )  -- Assign 4 to 'price4'
            },
            "Index", [Value1],  -- 'Index' column represents the position of each price
            "Price", [Value2]   -- 'Price' column represents the actual price values
        ),
        NOT ( ISBLANK ( [Price] ) )  -- Filter out rows where 'Price' is blank
    )

-- Combine the non-blank prices into a string separated by "|" using CONCATENATEX, 
-- and sort the prices by 'Index' (ascending order).
VAR _concat =
    CONCATENATEX ( _tbl, [Price], "|", [Index], ASC )

-- Calculate the length of the concatenated string (number of price values).
VAR _len =
    PATHLENGTH ( _concat )

-- Extract the latest (last) price from the concatenated string.
VAR _latestprice =
    PATHITEM ( _concat, _len, 1 )

-- Calculate the difference between the first price (_price1) and the latest price (_latestprice).
VAR _diff = _price1 - _latestprice

-- Return the price erosion calculation as the difference divided by the length of the prices,
-- and then divide by the initial price (_price1) to normalize the value.
RETURN
    DIVIDE ( DIVIDE ( _diff, _len ), _price1 )

danextian_0-1743480554778.png

Note: Index in the _tbl variable is important as CONCATENATEX combines values by ascending order if no order column is specified.





Dane Belarmino | Microsoft MVP | Proud to be a Super User!

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


"Tell me and I’ll forget; show me and I may remember; involve me and I’ll understand."
Need Power BI consultation, get in touch with me on LinkedIn or hire me on UpWork.
Learn with me on YouTube @DAXJutsu or follow my page on Facebook @DAXJutsuPBI.

View solution in original post

6 REPLIES 6
danextian
Super User
Super User

Hi @tomekm 

 

Try the following:

Price erosion = 
-- Capture the value from the 'price1' column of the table.
VAR _price1 = tbl[price1]

-- Create a filtered table '_tbl' using SELECTCOLUMNS, assigning indices (1, 2, 3, 4) to prices.
-- The SELECTCOLUMNS function assigns column names ("Index" and "Price") to the two columns.
-- Then, the FILTER function removes any rows where 'Price' is blank.
VAR _tbl =
    FILTER (
        SELECTCOLUMNS (
            {
                ( 1, tbl[price1] ), -- Assign 1 to 'price1'
                ( 2, tbl[price2] ), -- Assign 2 to 'price2'
                ( 3, tbl[price3] ), -- Assign 3 to 'price3'
                ( 4, tbl[price4] )  -- Assign 4 to 'price4'
            },
            "Index", [Value1],  -- 'Index' column represents the position of each price
            "Price", [Value2]   -- 'Price' column represents the actual price values
        ),
        NOT ( ISBLANK ( [Price] ) )  -- Filter out rows where 'Price' is blank
    )

-- Combine the non-blank prices into a string separated by "|" using CONCATENATEX, 
-- and sort the prices by 'Index' (ascending order).
VAR _concat =
    CONCATENATEX ( _tbl, [Price], "|", [Index], ASC )

-- Calculate the length of the concatenated string (number of price values).
VAR _len =
    PATHLENGTH ( _concat )

-- Extract the latest (last) price from the concatenated string.
VAR _latestprice =
    PATHITEM ( _concat, _len, 1 )

-- Calculate the difference between the first price (_price1) and the latest price (_latestprice).
VAR _diff = _price1 - _latestprice

-- Return the price erosion calculation as the difference divided by the length of the prices,
-- and then divide by the initial price (_price1) to normalize the value.
RETURN
    DIVIDE ( DIVIDE ( _diff, _len ), _price1 )

danextian_0-1743480554778.png

Note: Index in the _tbl variable is important as CONCATENATEX combines values by ascending order if no order column is specified.





Dane Belarmino | Microsoft MVP | Proud to be a Super User!

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


"Tell me and I’ll forget; show me and I may remember; involve me and I’ll understand."
Need Power BI consultation, get in touch with me on LinkedIn or hire me on UpWork.
Learn with me on YouTube @DAXJutsu or follow my page on Facebook @DAXJutsuPBI.

It works. Thank you!

Ashish_Mathur
Super User
Super User

Hi,

Share some sample raw data to work with.  Share data in a format that can be pasted in an MS Excel file.


Regards,
Ashish Mathur
http://www.ashishmathur.com
https://www.linkedin.com/in/excelenthusiasts/
ryan_mayu
Super User
Super User

@tomekm 

you can select the first column and unpivot other columns in pq

 

11.png12.png

 

then create a measure

 

Measure =
var _last=max('Table'[Attribute])
var _first=min('Table'[Attribute])
return (maxx(FILTER('Table','Table'[Attribute]=_first),'Table'[Value])-maxx(FILTER('Table','Table'[Attribute]=_last),'Table'[Value]))/COUNTROWS('Table')/maxx(FILTER('Table','Table'[Attribute]=_first),'Table'[Value])
 
13.PNG
 
pls see the attachment below




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

Proud to be a Super User!




Thank you, but I really need to be able to accomplish this using DAX only, and not through PQ. Any ideas of how to solve this? Appreciate it. 

@tomekm 

then you can try this

 

Column =
var _count=ISBLANK('Table'[price3])+ISBLANK('Table'[price4])
return SWITCH(TRUE(),_count=0,('Table'[price1]-'Table'[price4])/4/'Table'[price1],_count=1,('Table'[price1]-'Table'[price3])/3/'Table'[price1],('Table'[price1]-'Table'[price2])/2/'Table'[price1])
 
11.png




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

Proud to be a Super User!




Helpful resources

Announcements
Power BI DataViz World Championships

Power BI Dataviz World Championships

The Power BI Data Visualization World Championships is back! Get ahead of the game and start preparing now!

December 2025 Power BI Update Carousel

Power BI Monthly Update - December 2025

Check out the December 2025 Power BI Holiday Recap!

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.