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

The Power BI Data Visualization World Championships is back! It's time to submit your entry. Live now!

Reply
PythonMaster11
Regular Visitor

Loop function based on keyword

Hello all,

 

I'm trying to find the duration of each job my robot is doing. Process Operations vary from 3 - 50+ so I figured the best way to calculate the duration was to identify the keyword "Write Material Information" and assign the corresponding Start Time to variable t1. Then search for the vary next instance of "Update Material Position" and assign the corresponding Start Time/End time to variable t2 (FYI, Start Time & End Time are always the same value at the end of each job). After that, create a custom column to calculate the Job Duration via T=t2-t1. Then the function would repeat to find the next keyword "Write Material Information" and start all over (there are 20,000+ rows to go through). Here's a little picture to help. I'm new to VBA and Power Query so thanks in advance.

 

 

Power Query 04.png

1 ACCEPTED SOLUTION

Hi @PythonMaster11 ,

 

Try pasting this into a new blank query:

 

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("jZA9C8IwFEX/imTukJe0Nc0mTg5CQcShdAiaaECbEuPgvzf247W42PWcB/feV1Xk5G3Qq70K2lt1X+0a4/xDBesakhBgkuYyy0mdVKT17gwDXEsqEDKEQBHyAQpJoYPH9qLmSaV72lmMkNDf/SsEfB4DEwSEOUXKeEdV48JN+zJKVCld0CveZWxRL16Ml98KQvQ0peP+qw5bZ4zWk5j+mhdIhx1vHTa/paNlfUQnDuFlDBouFsyJd1mcXX8A", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [robotAction = _t, startTime = _t]),
    chgTypes = Table.TransformColumnTypes(Source,{{"robotAction", type text}, {"startTime", type time}}),
    addRandomBatchID = Table.AddColumn(chgTypes, "randomBatchID", each if [robotAction] = "Write Material Information" then List.Random(1) else {null}),
    expandRandomBatchID = Table.TransformColumns(addRandomBatchID, {"randomBatchID", each if _ = null then null else Text.Combine(List.Transform(_, Text.From)), type text}),
    replaceBlanks = Table.ReplaceValue(expandRandomBatchID,"",null,Replacer.ReplaceValue,{"randomBatchID"}),
    fillDownBatchID = Table.FillDown(replaceBlanks,{"randomBatchID"}),
    groupBatchID = Table.Group(fillDownBatchID, {"randomBatchID"}, {{"data", each _, type table [robotAction=nullable text, startTime=nullable time, randomBatchID=nullable text]}, {"minStart", each List.Min([startTime]), type nullable time}, {"maxStart", each List.Max([startTime]), type nullable time}}),
    expandDataColumn = Table.ExpandTableColumn(groupBatchID, "data", {"robotAction", "startTime"}, {"robotAction", "startTime"})
in
    expandDataColumn

 

 

It's a bit messy, and does rely on your data being in the correct order, but will hopefully inspire a cleaner solution if required.

 

Summary:

1) addRandomBatchID = adds a 1 item list of random numbers next to each process start (to identify a process batch)

2) expandRandomBatchID = expand list created in 1)

3) replaceBlanks = switch blanks for nulls - was lazy here!

4) fillDownBatchID = fill down our random number to the rest of each batch - this is why it's important original data is in the correct order beforehand

5) groupBatchID = group on our new batch ID, creatin All Rows, MIN, MAX, aggregate columns

6) expandDataColumn = expand the nested tables in [data] to get our original info back

 

Based on your actual data, you would probably shortcut this and just add a SUM of [Start to End] at the Group By stage along with an All Rows to get the original data back.

 

This gives the following output:

BA_Pete_0-1646239258714.png

 

Pete



Now accepting Kudos! If my post helped you, why not give it a thumbs-up?

Proud to be a Datanaut!




View solution in original post

8 REPLIES 8
Anonymous
Not applicable

You could filter your rows to include only the Rows with Update and Write. Sort by StartTime. Then you could use Table.Split(PriorStepName, 2). This will give you a column of nested two row tables, and you can now add a column like:

 

= List.Transform(PriorStep, "Duration" each Table.AddColumn( _, [StartTime]{1} - [StartTime]{0}))

 

Now you can expand the list of tables, and go back to the step before we filter, and join on that step as the table name, your last step name as the right table, with Robot Action and Start Time as your join columns.

 

--Nate

 

--Nate

BA_Pete
Super User
Super User

Hi @PythonMaster11 ,

 

I'm sure I already know the answer to this, but just in case: Are there other columns that give a robot ID and an 'Action Batch' ID?

 

Pete



Now accepting Kudos! If my post helped you, why not give it a thumbs-up?

Proud to be a Datanaut!




Unfortunately, there are not. Besides a Date field, all I have are the columns you see in the picture. 

Hi @PythonMaster11 ,

 

Try pasting this into a new blank query:

 

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("jZA9C8IwFEX/imTukJe0Nc0mTg5CQcShdAiaaECbEuPgvzf247W42PWcB/feV1Xk5G3Qq70K2lt1X+0a4/xDBesakhBgkuYyy0mdVKT17gwDXEsqEDKEQBHyAQpJoYPH9qLmSaV72lmMkNDf/SsEfB4DEwSEOUXKeEdV48JN+zJKVCld0CveZWxRL16Ml98KQvQ0peP+qw5bZ4zWk5j+mhdIhx1vHTa/paNlfUQnDuFlDBouFsyJd1mcXX8A", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [robotAction = _t, startTime = _t]),
    chgTypes = Table.TransformColumnTypes(Source,{{"robotAction", type text}, {"startTime", type time}}),
    addRandomBatchID = Table.AddColumn(chgTypes, "randomBatchID", each if [robotAction] = "Write Material Information" then List.Random(1) else {null}),
    expandRandomBatchID = Table.TransformColumns(addRandomBatchID, {"randomBatchID", each if _ = null then null else Text.Combine(List.Transform(_, Text.From)), type text}),
    replaceBlanks = Table.ReplaceValue(expandRandomBatchID,"",null,Replacer.ReplaceValue,{"randomBatchID"}),
    fillDownBatchID = Table.FillDown(replaceBlanks,{"randomBatchID"}),
    groupBatchID = Table.Group(fillDownBatchID, {"randomBatchID"}, {{"data", each _, type table [robotAction=nullable text, startTime=nullable time, randomBatchID=nullable text]}, {"minStart", each List.Min([startTime]), type nullable time}, {"maxStart", each List.Max([startTime]), type nullable time}}),
    expandDataColumn = Table.ExpandTableColumn(groupBatchID, "data", {"robotAction", "startTime"}, {"robotAction", "startTime"})
in
    expandDataColumn

 

 

It's a bit messy, and does rely on your data being in the correct order, but will hopefully inspire a cleaner solution if required.

 

Summary:

1) addRandomBatchID = adds a 1 item list of random numbers next to each process start (to identify a process batch)

2) expandRandomBatchID = expand list created in 1)

3) replaceBlanks = switch blanks for nulls - was lazy here!

4) fillDownBatchID = fill down our random number to the rest of each batch - this is why it's important original data is in the correct order beforehand

5) groupBatchID = group on our new batch ID, creatin All Rows, MIN, MAX, aggregate columns

6) expandDataColumn = expand the nested tables in [data] to get our original info back

 

Based on your actual data, you would probably shortcut this and just add a SUM of [Start to End] at the Group By stage along with an All Rows to get the original data back.

 

This gives the following output:

BA_Pete_0-1646239258714.png

 

Pete



Now accepting Kudos! If my post helped you, why not give it a thumbs-up?

Proud to be a Datanaut!




Hey Pete, I'm very new and don't know how to paste the formula into a blank query (from Other Sources, right?). I assumed I would merge the two queries after this? Once I got that figured out I was going to create a column that calculated the difference between max and min to display the duration of each job. Thanks for your help thus far.

Hi @PythonMaster11 ,

 

In Power Query go to New Source, select Blank Query, then with that query selected, go to Home tab > Advanced Editor then paste my code completely over the default code in there.

Once you hit enter, it will generate the table I've created with all the steps that you can click through to see what is happening at each step.

 

Pete



Now accepting Kudos! If my post helped you, why not give it a thumbs-up?

Proud to be a Datanaut!




Does "write" always follow "update"?  Or might there be extra lines in between?

Yes. Write and Update are unique keywords to mark the start and end of any given job. 

Helpful resources

Announcements
Power BI DataViz World Championships

Power BI Dataviz World Championships

The Power BI Data Visualization World Championships is back! It's time to submit your entry.

January Power BI Update Carousel

Power BI Monthly Update - January 2026

Check out the January 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.