skip to content

In Power BI, when should you use a bridge table instead of a many-to-many cardinality relationship?

level: seniorimportance: should knowfreq 55%

answer

  1. one option is quick, one is safe
  2. weak relationships behave differently at the edges
  3. what happens to keys that do not match?
  4. users want something to slice by
  5. facts should meet through a dimension

basics

~20 s

Use a bridge table whenever you need strong relationships, a slicer over the shared keys, or reliable totals. Power BI's many-to-many cardinality creates a limited relationship: no blank row for unmatched keys, no RELATED, and totals that can stop matching the visible rows.

solid answer

~50 s

Power BI gives you two ways to relate tables whose keys repeat on both sides. Setting the relationship cardinality to **many-to-many** joins them directly on the shared column — quick, but it creates a *limited* (weak) relationship. Limited relationships add no blank row for unmatched keys, so orphan rows silently drop out of filtered results while remaining in unfiltered totals, and `RELATED` cannot traverse them from row context. The alternative is a **bridge table**: a table of the distinct shared keys, related one-to-many to each side, so both relationships stay regular. Prefer the bridge when the shared key is a genuine business entity users should slice by — a `Date` table between `Sales` and `Budget`, an `Account` dimension between customers and transactions — or when you need predictable blank-row behaviour and `RELATED`. Reach for many-to-many cardinality only for a small, well-understood join where you have checked that both key sets match.

code

text · 9 lines
text
-- avoid: two facts joined directly
Sales(MonthKey) *---* Budget(MonthKey)     -- limited, fans out

-- prefer: conformed dimension at the coarsest common grain
         Month(MonthKey PK, MonthName, Year)
           1 |                 | 1
             v                 v
        Sales(MonthKey)   Budget(MonthKey)
-- both relationships regular, one slicer filters both

go deeper

for a junior

Be ready to recognise the shape: when the join column repeats on both sides, Power BI needs either a many-to-many cardinality setting or an extra table of distinct keys in between.

for a middle

Explain what a bridge buys you — two regular one-to-many relationships, a table users can slice by, and blank-row protection — versus the direct many-to-many option's limited-relationship behaviour.

for a senior

Diagnose the wrong numbers: know that limited relationships drop unmatched rows from filtered results, that RELATED will not traverse them, and that two facts joined directly fan out into a cross product.

for a principal

Own the pattern library: decide which shared keys become governed conformed dimensions in the model rather than ad-hoc many-to-many joins, so a dozen reports built by different teams reconcile against each other.

## The situation You have two tables whose join column repeats on both sides. Classic cases: `Sales` at daily/product grain and `Budget` at monthly/category grain, both carrying `MonthKey`; or `Customer` and `Account` where a customer holds several accounts and an account is held jointly by several customers. Power BI offers two answers, and the interview question is which one and why. ## Option A: many-to-many cardinality Select `Many to many (*:*)` in the relationship dialog and relate the two tables directly on the repeated column. It works immediately and requires no new tables. What you have created, though, is a **limited relationship** (the engine's term; also called a weak relationship), and limited relationships differ from regular ones in ways that produce wrong numbers rather than errors: - **No blank row.** A regular relationship materialises a blank member on the one side so unmatched or null many-side keys still land somewhere and the grand total stays whole. A limited relationship does not. Unmatched rows are excluded from cross-filtered results but still counted in an unfiltered total, so the visible rows stop summing to the total and nothing on the page explains the gap. - **`RELATED` does not work across it.** Row-context lookups need a regular relationship, so a calculated column that walks the relationship simply cannot be written. - **No shared-key entity.** Users have no table to slice by. If they select a month, which table's month are they selecting? Whichever one you exposed — the other side is filtered only indirectly. Relationships that span source groups in a **composite model** (for example an import table related to a DirectQuery table) are limited for the same reason, and inherit the same caveats. ## Option B: a bridge table Build a table of the **distinct values** of the shared key and relate it one-to-many to each side. Both relationships are now regular, and the bridge itself becomes the thing users filter on: ```text Month (bridge: distinct MonthKey, MonthName, Year) 1 1 | | v v Sales Budget (many rows) (many rows) ``` Now a slicer on `Month[MonthName]` filters both fact tables identically, each relationship gets blank-row protection, and `RELATED` works from either fact table into the bridge. For two fact tables at different grains this is simply the conformed-dimension pattern expressed in Power BI: relate both facts to a shared dimension **at the coarsest common grain** rather than to each other. Note that filtering flows *down* from the bridge to both sides with the default single direction — which is exactly what you want for two fact tables. The genuine many-to-many case (customers and accounts) needs one more piece: a bridge holding the *pairs*, sitting between the two dimensions. Because a filter must travel up one relationship and down the other, that pattern needs bidirectional propagation across the bridge — either set on the relationship or, more surgically, applied per measure with `CROSSFILTER`. ## Choosing Use a **bridge** when: the shared key is a business entity people want to see and slice (dates, months, categories, accounts); you need `RELATED`; you need blank-row protection and totals that reconcile; more than two tables share the key; or the model will be consumed by self-service authors who did not build it. Use **many-to-many cardinality** when: the join is small and contained, you have verified both key sets match, no calculated column needs `RELATED`, and adding a table would be ceremony. It is a legitimate tool — Microsoft added it precisely because bridges plus bidirectional filters were being over-used — but it is a considered choice, not a default. ## The mistake to avoid entirely Do not relate two fact tables **directly** because they happen to share a column. `Sales` joined straight to `Budget` on `MonthKey` gives every sales row a partner for every budget row of that month, and any measure that spans both starts multiplying rows. The symptom is a number that is wrong by a suspiciously round factor. Facts talk to each other **through** dimensions, never directly — that is what the star schema is for, and Power BI's relationship engine assumes it. ## What interviewers listen for The answer they want names the limited-relationship behaviour explicitly — blank rows, `RELATED`, totals not reconciling — rather than saying bridges are "best practice". A senior answer also separates the two distinct scenarios that both look like many-to-many: *two facts at different grains* (solved by a conformed dimension) and *two dimensions with a genuine pair-wise relationship* (solved by a bridge of pairs plus scoped bidirectional propagation).

  • Why should two fact tables never be related directly on a shared column?
    Because each row on one side pairs with every matching row on the other, so any measure spanning both fans out and multiplies. The symptom is a total wrong by a suspiciously round factor. Facts should meet through a shared dimension at the coarsest common grain, which filters both consistently without creating a cross product.
  • What is a limited relationship, and where do they appear besides many-to-many cardinality?
    A limited or weak relationship is one where the engine cannot rely on a unique key on either side to guarantee integrity. Besides many-to-many cardinality, relationships that cross source groups in a composite model are limited. They add no blank row, cannot be traversed by RELATED from row context, and let unmatched rows silently vanish from filtered results.
  • How do you model customers and accounts where each can belong to several of the other?
    Create a bridge table of the distinct customer-account pairs and relate it one-to-many from each dimension. Filters must travel up one relationship and down the other, so enable bidirectional propagation across the bridge, ideally scoped to the measures that need it with CROSSFILTER rather than set model-wide.

saying these in an interview costs you the question

  • Relates two fact tables directly on a shared date or month column
  • Calls many-to-many cardinality a drop-in replacement for a bridge
  • Unaware that limited relationships add no blank row for unmatched keys
  • Assumes RELATED works across any relationship
  • Adds bidirectional filtering everywhere instead of building the shared dimension

context