Forum Discussion
Some help with loops, please. and an additional question
I have a master data set in a table in Power BI. Two of the relevent fields in the master dataset are 'Name' and 'Contract'. From this master dataset, I have contructed two other tables using the DISTINCT function. A Name table of unique names, and a Contract table of unique contract names, from the dataset.
| Name |
| Bob Smith |
| Sally Strumpet |
| Joe Blow |
And...
| Contract |
| Contract 1 |
| Contract 2 |
| Contract 3 |
Rather than using an additional data file, I would like to [partially] contruct a 'Billing Rates' Table that for each Contract, loops thru all the names to create entries in the Billing Rates table. (For each contract, loop thru all the names.) Conceptually looking like this:
| Contract | Name |
| Contract 1 | Bob Smith |
| Contract 1 | Sally Strumpet |
| Contract 1 | Joe Blow |
| Contract 2 | Bob Smith |
| Contract 2 | Sally Strumpet |
| Contract 2 | Joe Blow |
| Contract 3 | Bob Smith |
| Contract 3 | Sally Strumpet |
| Contract 3 | Joe Blow |
I am unpracticed in [nested] loops in DAX to accomplish this. I was unable to modify code from the other examples, so far.
I also have a question:
Once I am able (with your help, hopefully) to use looping to construct the first two columns the Rates Table above, will power BI allow me to add a third column for manual entry of the 'billing rate' for each row of the billing rate table? Or are there no manual columns allowed in a table that is partially generated? If I wouldn't be able to manually enter the billing rates in a final column, trying not to use an additional external file would be pointless.
My Goal for the final table is this, with me entering the rates manually in the third column, of course.
| Contract | Name | Billing Rate |
| Contract 1 | Bob Smith | |
| Contract 1 | Sally Strumpet | |
| Contract 1 | Joe Blow | |
| Contract 2 | Bob Smith | |
| Contract 2 | Sally Strumpet | |
| Contract 2 | Joe Blow | |
| Contract 3 | Bob Smith | |
| Contract 3 | Sally Strumpet | |
| Contract 3 | Joe Blow |
Another (longer) way:
Step 1: Create the Billing Rates Table with All CombinationsAssuming your master table is called MasterData, and it contains the columns Name and Contract, you've already created:
- A table called Names with unique names:dax
Names = DISTINCT(MasterData[Name]) - A table called Contracts with unique contracts:
Contracts = DISTINCT(MasterData[Contract])To create the Billing Rates table that contains every possible combination of Contract + Name (i.e. a cross join / Cartesian product), use this DAX expression for a new table:
Billing Rates = SELECTCOLUMNS( CROSSJOIN( Contracts, Names ), "Contract", [Contract], "Name", [Name] )
Or, if you prefer to write it more explicitly using VALUES (especially useful if your dimension tables already use VALUES or DISTINCT):
Billing Rates = SELECTCOLUMNS( CROSSJOIN( VALUES(MasterData[Contract]), VALUES(MasterData[Name]) ), "Contract", [Contract], "Name", [Name] )
Both versions produce the exact table structure you showed:- Contract 1 – Bob Smith
- Contract 1 – Sally Strumpet
- Contract 1 – Joe Blow
- Contract 2 – Bob Smith
...and so on for all combinations.
and the second question: for sum of BILLS per person per contract (most likely what you mean):Billing Rates = ADDCOLUMNS( CROSSJOIN( VALUES(MasterData[Contract]), VALUES(MasterData[Name]) ), "Contract", [Contract], "Name", [Name], "Billing Rate", CALCULATE( SUM(MasterData[BILLS]), MasterData[Contract] = EARLIER([Contract]), MasterData[Name] = EARLIER([Name]) ) )
I hope this helps, if so please mark it as a solution. Kudos are welcome!- A table called Names with unique names:
4 Replies
- pcoley
Super User
Dan_at_TWE Please try creating the table as follow; Changing the names of Table and fields as needed:
Summary Table = SUMMARIZE ( MasterData, MasterData[Contract], MasterData[Name], "Billing Rate", SUM ( MasterData[Bills] ) )
I hope this helps, if so please mark it as a solution; Kudos are welcome!- pcoley
Super User
Another (longer) way:
Step 1: Create the Billing Rates Table with All CombinationsAssuming your master table is called MasterData, and it contains the columns Name and Contract, you've already created:
- A table called Names with unique names:dax
Names = DISTINCT(MasterData[Name]) - A table called Contracts with unique contracts:
Contracts = DISTINCT(MasterData[Contract])To create the Billing Rates table that contains every possible combination of Contract + Name (i.e. a cross join / Cartesian product), use this DAX expression for a new table:
Billing Rates = SELECTCOLUMNS( CROSSJOIN( Contracts, Names ), "Contract", [Contract], "Name", [Name] )
Or, if you prefer to write it more explicitly using VALUES (especially useful if your dimension tables already use VALUES or DISTINCT):
Billing Rates = SELECTCOLUMNS( CROSSJOIN( VALUES(MasterData[Contract]), VALUES(MasterData[Name]) ), "Contract", [Contract], "Name", [Name] )
Both versions produce the exact table structure you showed:- Contract 1 – Bob Smith
- Contract 1 – Sally Strumpet
- Contract 1 – Joe Blow
- Contract 2 – Bob Smith
...and so on for all combinations.
and the second question: for sum of BILLS per person per contract (most likely what you mean):Billing Rates = ADDCOLUMNS( CROSSJOIN( VALUES(MasterData[Contract]), VALUES(MasterData[Name]) ), "Contract", [Contract], "Name", [Name], "Billing Rate", CALCULATE( SUM(MasterData[BILLS]), MasterData[Contract] = EARLIER([Contract]), MasterData[Name] = EARLIER([Name]) ) )
I hope this helps, if so please mark it as a solution. Kudos are welcome!- pcoley
Super User
And finally, using Power Query:
- In Power Query Editor → select your MasterData query (or reference it if you want to keep the original unchanged).
- Home tab → Group By.
- In the Group By dialog:
- Basic mode is fine if you only group by two columns.
- Group by: Contract and Name (click "Advanced" to add the second column if needed).
- New column name: e.g. Total Bills (or Billing Rate, Sum of Bills, etc.).
- Operation: Sum.
- Column: Bills.
- Click OK.
- A table called Names with unique names: