In the first post in this series I showed how to use the new Excel Lambda helper functions to return an array containing all the items in a set. That isn’t very useful on its own, so in this post I’ll show you how to generate an entire dynamic table using Excel cube functions and Lambda helper functions.

In this post I’ll be using the same source data as in my previous post: a table containing sales data with just two columns.

With this table added to the Excel Data Model/Power Pivot, I created two measures:

I then created created two sets using CubeSet containing the sets of Products (in cell B2 of my worksheet) and Measures (in cell B4) to use in my table:

=CUBESET("ThisWorkbookDataModel", "[Sales].[Product].[Product].MEMBERS", "Product Set") =CUBESET("ThisWorkbookDataModel", "{[Measures].[Sales Amount], [Measures].[Forecast Sales]}", "Measure Set")

Here are the formulas shown in the worksheet:

And here’s the output – remember you only see the text in the third parameter displayed in the cell:

Now, here’s the fun part – a single formula that takes these sets and builds a table with the Measures on columns and the Products on rows:

=MAKEARRAY( CUBESETCOUNT(B2)+1, CUBESETCOUNT(B4)+1, LAMBDA(r,c, SWITCH( TRUE(), AND(r=1,c=1), "", c=1, CUBERANKEDMEMBER("ThisWorkbookDataModel",$B$2,r-1), r=1, CUBERANKEDMEMBER("ThisWorkbookDataModel",$B$4,c-1), CUBEVALUE("ThisWorkbookDataModel", CUBERANKEDMEMBER("ThisWorkbookDataModel",$B$2,r-1), CUBERANKEDMEMBER("ThisWorkbookDataModel",$B$4,c-1) ) ) ) )

Here’s what this formula returns:

How does this work? Going through the MakeArray function step-by-step:

- The first two parameters specify that the output will be an array with one more row than there are items in the Product set and one more column than there are items in the Measures set.
- The third parameter returns a Lambda that is called for every cell in this array. This Lambda contains a Switch with the following conditions:
- For the top-left cell in the array, return a blank value
- In the first column, use the CubeRankedMember function to return the Products on the rows of the table
- In the first row, use the CubeRankedMember function to return the Measures on the columns of the table
- In the body of the table, use the CubeValue function to return the values

Here’s a slightly more ambitious version that returns the same table but adds a total row to the bottom:

= LET( NumberOfRows, CUBESETCOUNT(B2)+2, NumberOfColumns, CUBESETCOUNT(B4)+1, MAKEARRAY( NumberOfRows, NumberOfColumns, LAMBDA(r,c, SWITCH( TRUE(), AND(r=1,c=1), "", AND(r=NumberOfRows,c=1), "Total", r=NumberOfRows, CUBEVALUE("ThisWorkbookDataModel", $B$2, CUBERANKEDMEMBER("ThisWorkbookDataModel",$B$4,c-1)), c=1, CUBERANKEDMEMBER("ThisWorkbookDataModel",$B$2,r-1), r=1, CUBERANKEDMEMBER("ThisWorkbookDataModel",$B$4,c-1), CUBEVALUE("ThisWorkbookDataModel", CUBERANKEDMEMBER("ThisWorkbookDataModel",$B$2,r-1), CUBERANKEDMEMBER("ThisWorkbookDataModel",$B$4,c-1)) ) ) ) )

Two extra things to note here:

- This is a great example of a complex formula where the new Excel Let function can be used to improve readability and prevent the same value being evaluated twice.
- The values in the Total row are calculated in the Excel Data Model, not on the worksheet, by using the CubeSet function inside the CubeValue function. This means that the totals will be consistent with what you see in a PivotTable and therefore correct

This is still very much a proof-of-concept. I need to look at the performance of this approach (it may not be optimal and may need tuning), and I’m not sure how a table like this could be formatted dynamically (especially the Total row). It is exciting though!

Great post @Chris! Do you think this approach could ever be used to display dynamic parent child relationships e.g. Group “Apple” children “Granny Smith”, “Pink Lady”, etc.? In an ideal world even expandable? I will play with this a bit as well. In the past I have used Pivot Table parts (row hierarchies) in combination with CUBEVALUE with acceptable results for dynamic asymmetric reports. Problem is CUBEVALUE is still very slow.

It might work, but I don’t think it would fix the performance problem

Very nice academic article. Unfortunately, it cannot be used in practice without the MAKEARRAY function. How much longer will dynamic array functions be available only to insiders?

Hello, Chris. You are missing a – sign between the r and the 1 in the last CUBERANKEDMEMBER function in the first formula, the one without the total row. Cheers!

Thanks! I’ve fixed it now.