The three many-to-many scenarios in a semantic model and the bridge-table or relationship design each one needs.
From Ultra Transcenders DP-600 by Tony Rough (coming December 2026)
“Many-to-many” describes three different requirements in Learn’s guidance, and each has a different recommended design. Choosing the wrong one produces either wrong numbers or a model that can only be grouped one way.
| Scenario | Example | Recommended design |
|---|---|---|
| Relate two many-to-many dimensions | Customers and accounts (joint account holders) | Bridging (factless fact) table with two one-to-many relationships, one of them bi-directional |
| Relate two fact tables | Order lines and fulfilments sharing an order ID | Don’t relate facts directly; add shared dimensions with one-to-many relationships to both |
| Relate a fact stored at a higher grain | Targets by category and year; products at product level | Date: store first day of period, one-to-many to the date table. Non-date: many-to-many relationship, single direction from dimension to fact, plus measure logic |
The steps Learn gives for the bridge pattern are:
Totals are non-additive: two joint holders of the same account each show its full balance, so the customer subtotals add up to more than the grand total. Learn suggests explaining this to report users with text or visual header tooltips. Relating two dimensions directly with many-to-many cardinality isn’t recommended, because dimension tables should always use their ID column as the “one” side.
When targets are stored by category but products are at product level, a many-to-many relationship on Category (filtering from Product to Target) lets category slicing work, but grouping by a lower-level column such as Color filters targets by every category that colour appears in. Learn’s fix is to hide summarisable fact columns and return BLANK when a lower-level column is filtered:
Target Quantity =
IF (
NOT ISFILTERED ( 'Product'[ProductID] )
&& NOT ISFILTERED ( 'Product'[Product] )
&& NOT ISFILTERED ( 'Product'[Color] ),
SUM ( Target[TargetQuantity] )
)
The same idea applies to dates: store the first date of the target period, relate it one-to-many to the date table, and return BLANK when Date or Month is filtered.
Common trap: Relating two fact tables directly with a many-to-many relationship because they share an order number - Learn recommends against it: visuals can then only group by that one column, and the limited relationship can drop rows when integrity is broken; add shared dimension tables instead.
This note is one section of Ultra Transcenders DP-600: Implementing Analytics Solutions Using Microsoft Fabric, an independent study guide that explains every topic the exam covers by technology, with comparison tables, diagrams and the common traps, plus a glossary linked to Microsoft Learn.
Due on Amazon in December 2026, in Kindle and paperback editions.
About the book · DP-600 terms in the glossary · All DP-600 study notes
How the two Direct Lake flavours differ in table discovery, permission checks, fallback and unsupported cases, and which one to choose.
When each table storage mode fits a semantic model, based on data size, latency, source security and capacity.
What each Fabric workspace role can do across Power BI, data engineering, warehousing and real-time items.
Which items and settings a deployment copies or leaves alone, and how data source and parameter rules point each stage at its own data.
How data type, team skills, write needs and transactions decide between Fabric's lakehouse, warehouse, eventhouse and other stores.
What the Warehouse can do that a lakehouse's read-only SQL analytics endpoint can't, and when to use each.
How data volume, transformation needs, skills and latency decide which Fabric tool should copy data into OneLake.