Bill of Material (BOM) Explosion Part2: Costing in Excel and PowerBI

Following up on the BOM-explosion: A comment reminded me that I had missed to present the costing techniques to calculate the total costs of each (sub)-product.

Reversing the aggregation direction

What I had shown is how to “aggregate” from parent down to child-level to retrieve the total quantity of each component within a BOM (“How many of each (sub-) components do we have to order (or build) for that bike?”) (1).

Now we reverse the aggregation direction and aggregate the total (!) quantities back up to the parents (2).

And, as this doesn’t make too much sense in an economical way, the second aggregation will be their prices (3). This will give us the sum of all part-costs (“How much will the order of all the parts cost us?”). This is also very useful for planning purposes or reconciliation of prices for intermediate products with your master data.

And if your model holds sales-data as well, you can calculate the totals costs of your total sales within each period. (4)

VAR 1: Using classical hierarchies

Using classical hierarchies, this becomes a fairly easy task: Flatten your hierarchy in the BOMReport-table and create a hierarchy in the datamodel. Then connect it to the DimProducts to retrieve the prices on ComponentID. If it is connected to the Sales-table as well, the measure “TotalCostH” will return the full production costs for all items sold:

  • CountPartsH :=
    CALCULATE ( SUM ( BOMReport[TotalQty] ), BOMReport[PurchaseItem] <> BLANK () )
  • CostPerAssemblyQtyH :=
    MAX ( DimProduct[Price] ) * [CountPartsH]
  • TotalCostH :=
    MAX ( FactSales[Sales] ) * MAX ( DimProduct[Price] )
    * [CountPartsH]

DAX Formatter by SQLBI

VAR2: Fully dynamic via bridge-table

If you want to have it fully dynamic and don’t want to create the hierarchies in the datamodel manually, you need to create a bridge-table like in the Easy-P&L, which holds all the rows for aggregation. I had to add the column with the total quantities from the report-table there as well because I couldn’t figure out how to do without. (If you have a clue how to tackle this with a measures instead, please come forward!)

Data model for dynamic hierarchy

Code to create the bridge-table

For every non-purchase item (the final product or any of its assembled sub-components) we are collecting all purchase items that go into it here. Then we expand it to create one row per purchase item for it so that we can connect it to the DimProduct to retrieve the purchase prices.

Download code for bridge-table: BOM2_BridgeTable.txt

Your reports shouldn’t hold any subtotals then, just drag “PathExplode” from the BOMReport into the row-section of your report and add the following measures:

  • CountPartsR :=
    SUM ( BOMBridgeNew[TotalQty] )
  • CostPerAssemblyQtyR :=
    SUMX ( BOMBridgeNew, MAX ( DimProduct[Price] ) * BOMBridgeNew[TotalQty] ),
  • TotalCostR :=
    SUMX (
    MAX ( FactSales[Sales] ) * MAX ( DimProduct[Price] )* BOMBridgeNew[TotalQty]),

DAX Formatter by SQLBI

Look how the filters flow through 4 tables in the last measure (considering that you drag a field from the BOMReport-table into your report): Here the DAX really shines!

Comparison of both methods:

The Hierarchy-version (“H”) will only evaluate values for the components which are purchase-items, while the “Bridge-table-version” (“R”) will evaluate all aggregated values on a row-level. Therefore you cannot use sub-totals in your report.

Subscribers can download the files: BOM Explosion Part2 and VAR2: BOM Explosion - Costing Var2


  • In the files attached, for practical reasons the DimProduct and FactSales are created referencing the bridge-table. In real-life, you should of course replace them with the tables from your system.
  • The file for VAR2 also holds the solution for VAR within that environment, so you can run it through within the bridge-table datamodel in parallel as well

The last part with BOM-Implosion (“Where Used-Analysis”) is out here.

Enjoy & stay queryious 🙂

Comments (5) Write a comment

  1. Pingback: # Excel Super Links #69 – shared by David Hager | Excel For You

  2. Hi Imke,

    I have no clue what this “Lengthening” of the BOM table is all about?

    The Bridge-table-version (“R”) can also evaluate only values for the components which are purchase-items. I removed TotalQty from the bridge table, put BOMReport[PathExplode] on the rows, and the following measures seem to work:

    CountPartsR :=
    SUM ( BOMReport[TotalQty] );
    BOMReport[PurchaseItem] <> BLANK ();

    TotalCostR :=
    MAX ( FactSales[Sales] ) * MAX ( DimProduct[Price] ) * SUM(BOMReport[TotalQty]);
    BOMReport[PurchaseItem] <> BLANK ();

    CostPerAssemblyQtyR :=
    MAX ( DimProduct[Price] ) * SUM(BOMReport[TotalQty]);
    BOMReport[PurchaseItem] <> BLANK ();


    • Thanks Frank, the measures are very smart!
      Pls give me some more hints what you’re referring to with “I have no clue what this “Lengthening” of the BOM table is all about?”.
      Thanks & cheers, Imke


Leave a Reply