Forum Discussion
Calculate row difference based on category / index.
Hi All,
I'm confronted with a nice puzzle in Power BI which I can't seem to solve.
Hoping you can help me to get into the right direction :)
The 'functional' question is easy. Say, there are locations and on all locations, trucks drive around (of course not every day). The trucks register the hours they have driven and I would like to calculate the hours they have driven per day (calculated based on the value of the previous day). The source data looks like this:
| Date | Location | Vehicle Tag | Counter |
| 1-4-2018 | Amsterdam | AB123 | 110 |
| 2-4-2018 | Amsterdam | AB123 | 118 |
| 4-4-2018 | Amsterdam | AB123 | 126 |
| 1-4-2018 | Rotterdam | RC234 | 500 |
| 2-4-2018 | Rotterdam | RC234 | 508 |
| 3-4-2018 | Rotterdam | RC234 | 510 |
Since the trucks belong to different locations, and don't drive around every day, I started with creating an index based on a unique key (Location & Vehicle Tag). Thanks to some posts by Eric_Zhang I've managed to do so, and now the data looks like this.
| Date | Location | Vehicle Tag | Counter | Key | Index |
| 1-4-2018 | Amsterdam | AB123 | 110 | AmsterdamAB123 | 1 |
| 2-4-2018 | Amsterdam | AB123 | 118 | AmsterdamAB123 | 2 |
| 4-4-2018 | Amsterdam | AB123 | 126 | AmsterdamAB123 | 3 |
| 1-4-2018 | Rotterdam | RC234 | 500 | RotterdamRC234 | 1 |
| 2-4-2018 | Rotterdam | RC234 | 508 | RotterdamRC234 | 2 |
| 3-4-2018 | Rotterdam | RC234 | 510 | RotterdamRC234 | 3 |
However, now comes the tricky part (at least for me): calculating the difference between the values (based on the combination of the Key and index). I've been puzzling with the logic described by Zubair_Muhammad in this post, or the suggestion from ImkeF described in this post. However, I simply cannot sort out how to incorporate the 'key' into the calculation.
Ultimately, the result would look like this:
| Date | Location | Vehicle Tag | Counter | Key | Index | Result |
| 1-4-2018 | Amsterdam | AB123 | 110 | AmsterdamAB123 | 1 | 110 |
| 2-4-2018 | Amsterdam | AB123 | 118 | AmsterdamAB123 | 2 | 8 |
| 4-4-2018 | Amsterdam | AB123 | 126 | AmsterdamAB123 | 3 | 8 |
| 1-4-2018 | Rotterdam | RC234 | 500 | RotterdamRC234 | 1 | 500 |
| 2-4-2018 | Rotterdam | RC234 | 508 | RotterdamRC234 | 2 | 8 |
| 3-4-2018 | Rotterdam | RC234 | 510 | RotterdamRC234 | 3 | 2 |
As said, any suggestion / help would be much appreciated! Thanks in advance!
Please copy and paste this code into the advanced editor and follow the steps. For performance reasons, the creation of the nested index and the fetching of the previoius row is included in one function ("MyFunction"), which is a bit of an advanced techique:
let Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMjDUNTDRNbRQ0lFyzC0uSS1KScwFsZ0MjYyBtKGhgVKsDlCZEQFlFhBlJviVGZlBlCEsDcovgSsLcjYyNgHSpgYYlmJXBrXUGL8ykBdiAQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [Date = _t, Location = _t, #"Vehicle Tag" = _t, Counter = _t]), #"Changed Type" = Table.TransformColumnTypes(Source,{{"Date", type date}, {"Location", type text}, {"Vehicle Tag", type text}, {"Counter", Int64.Type}}), WithKey = Table.AddColumn(#"Changed Type", "Key", each Text.Combine({[Location], [Vehicle Tag]}, ""), type text), MyFunction = (SourceTable as table) => let AddIndex = Table.AddIndexColumn(SourceTable , "Index", 0, 1), DiffToPrevious = Table.AddColumn(AddIndex, "DiffToPrevious", each if [Index]=0 then [Counter] else [Counter]-AddIndex{[Index]-1}[Counter]) in DiffToPrevious, Next = WithKey, #"Grouped Rows" = Table.Group(Next, {"Key"}, {{"All", each _, type table}}), #"Added Custom" = Table.AddColumn(#"Grouped Rows", "ExecuteFunction", each MyFunction([All])), #"Expanded ExecuteFunction" = Table.ExpandTableColumn(#"Added Custom", "ExecuteFunction", {"Date", "Location", "Vehicle Tag", "Counter", "Index", "DiffToPrevious"}, {"Date", "Location", "Vehicle Tag", "Counter", "Index", "DiffToPrevious"}) in #"Expanded ExecuteFunction"
3 Replies
- ImkeFCommunity Champion
Please copy and paste this code into the advanced editor and follow the steps. For performance reasons, the creation of the nested index and the fetching of the previoius row is included in one function ("MyFunction"), which is a bit of an advanced techique:
let Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMjDUNTDRNbRQ0lFyzC0uSS1KScwFsZ0MjYyBtKGhgVKsDlCZEQFlFhBlJviVGZlBlCEsDcovgSsLcjYyNgHSpgYYlmJXBrXUGL8ykBdiAQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [Date = _t, Location = _t, #"Vehicle Tag" = _t, Counter = _t]), #"Changed Type" = Table.TransformColumnTypes(Source,{{"Date", type date}, {"Location", type text}, {"Vehicle Tag", type text}, {"Counter", Int64.Type}}), WithKey = Table.AddColumn(#"Changed Type", "Key", each Text.Combine({[Location], [Vehicle Tag]}, ""), type text), MyFunction = (SourceTable as table) => let AddIndex = Table.AddIndexColumn(SourceTable , "Index", 0, 1), DiffToPrevious = Table.AddColumn(AddIndex, "DiffToPrevious", each if [Index]=0 then [Counter] else [Counter]-AddIndex{[Index]-1}[Counter]) in DiffToPrevious, Next = WithKey, #"Grouped Rows" = Table.Group(Next, {"Key"}, {{"All", each _, type table}}), #"Added Custom" = Table.AddColumn(#"Grouped Rows", "ExecuteFunction", each MyFunction([All])), #"Expanded ExecuteFunction" = Table.ExpandTableColumn(#"Added Custom", "ExecuteFunction", {"Date", "Location", "Vehicle Tag", "Counter", "Index", "DiffToPrevious"}, {"Date", "Location", "Vehicle Tag", "Counter", "Index", "DiffToPrevious"}) in #"Expanded ExecuteFunction"- AnonymousNot applicable
Hi Imke,
Just tried your proposed solution, and I got it working (more or less). Will spend a large amount of my day tomorrow re-reading / producing the solution steps. Awesome bit of code!!! Many many thanks!!!!
- Ashish_MathurSuper User
Hi,
This can be solved with a calculated column as well (without creating a key column).
=if(ISBLANK(LOOKUPVALUE(Data[Counter],Data[Date],CALCULATE(MAX(Data[Date]),FILTER(Data,Data[Location]=EARLIER(Data[Location])&&Data[Vehicle Tag]=EARLIER(Data[Vehicle Tag])&&Data[Date]<EARLIER(Data[Date]))),[Location],[Location],[Vehicle Tag],[Vehicle Tag])),[Counter],[Counter]-LOOKUPVALUE(Data[Counter],Data[Date],CALCULATE(MAX(Data[Date]),FILTER(Data,Data[Location]=EARLIER(Data[Location])&&Data[Vehicle Tag]=EARLIER(Data[Vehicle Tag])&&Data[Date]<EARLIER(Data[Date]))),[Location],[Location],[Vehicle Tag],[Vehicle Tag]))