11.4 Relationships in Power BI with Example: Cardinality and Direction
In short: A relationship tells Power BI which key column links two tables.
Quick answer: the short, self-contained version of this lesson is the guide Power BI Cardinality and Filter Direction.
Start with a problem
Ruhi adds a City slicer from DarkStore, but every city shows ₹2,100.
Explain simply
A relationship tells Power BI which key column links two tables. Filters flow from the one side (DarkStore) to the many side (Orders).
Show the data
Matrix with NO relationship:
| City | Amount (₹) |
|---|---|
| Kolhapur | 2,100 |
| Nashik | 2,100 |
| Pune | 2,100 |
About this data: This table uses columns: City, Amount (₹). This table uses columns: City, Total Sales (₹). This table uses columns: City (DarkStore), Total Sales. Values shown are the lesson examples already on this page (not a new dataset).
Fictional sample data. Practice file: visuals_orders_apr_may_2026.csv, dark_stores_maharashtra.csv (source: src/practice/).
Demonstrate
- Model view › drag DarkStore[Store] onto Orders[Store].
-
Check the dialog: Cardinality Many to one (*:1) from Orders, Cross filter direction Single, Make this relationship active ticked › OK.
Your result should look like this:
Relationship line DarkStore 1 ──► * Orders -
Look at the matrix again.
Your result should look like this:
City Amount (₹) Kolhapur 450 Nashik 800 Pune 850 -
Later, add Date[Date] 1 → * Orders[Order Date] in the same way (Date table: lesson 11.5).
Show the result
Your result should look like this (fictional sample):
| City | Total Sales (₹) |
|---|---|
| Pune | 850 |
| Nashik | 800 |
| Kolhapur | 450 |
| Total | 2,100 |
Explain what happened
Each order's Store now matches exactly one DarkStore row. A City filter selects stores, and the stores filter Orders along the arrow.
Explore further
- Inactive (dotted) relationships are used with USERELATIONSHIP (Module 13.12).
- Use Both direction only for a reason, such as the bridge table in 11.11.
Detailed reference for this lesson:
Relationships in Power BI with example (one-to-many) — in 30 seconds
What: A relationship tells Power BI which key column links two tables.
Why: Without it, a City slicer cannot filter the Orders table. Every city shows the same total.
Tiny example: No relationship: Pune ₹1,500, Nashik ₹1,500 (wrong). With relationship: Pune ₹1,200, Nashik ₹300.
Relationships in Power BI with example (one-to-many) — 30 सेकंदात
काय: Relationship Power BI ला सांगते की कोणता key column दोन tables ना जोडतो.
का: ती नसेल तर City slicer Orders table ला filter करू शकत नाही. प्रत्येक शहराला तोच total दिसतो.
छोटं उदाहरण: Relationship नाही: Pune ₹1,500, Nashik ₹1,500 (चूक). Relationship असेल: Pune ₹1,200, Nashik ₹300.
Relationships in Power BI with example (one-to-many) — 30 सेकंड में
क्या: Relationship Power BI को बताती है कि कौन-सा key column दो tables को जोड़ता है.
क्यों: उसके बिना City slicer Orders table को filter नहीं कर सकता. हर शहर में वही total दिखता है.
छोटा उदाहरण: Relationship नहीं: Pune ₹1,500, Nashik ₹1,500 (ग़लत). Relationship के साथ: Pune ₹1,200, Nashik ₹300.
First look at the data (before → after):
Same before / after tables as text
Before — Matrix with NO relationship (same total on every row)
| City (DarkStore) | Total Sales |
|---|---|
| Pune | ₹1,500 |
| Nashik | ₹1,500 |
| Total | ₹1,500 |
Formula / click path
Model view: drag DarkStore[Store ID] → Orders[Store ID]
Cardinality One to many (1:*) · Cross filter: Single
After — Matrix WITH the relationship
| City (DarkStore) | Total Sales |
|---|---|
| Pune | ₹1,200 |
| Nashik | ₹300 |
| Total | ₹1,500 |
Do it step by step:
- Click the Model view icon on the left.
- Drag Store ID from DarkStore and drop it on Store ID in Orders.
- Double-click the line. Check: One to many, Single, Active.
- Go back to Report view. The matrix now splits correctly.
- If you see a (Blank) row, some Orders Store IDs are missing from DarkStore. Fix the dimension.
एक-एक step करून बघा:
- डावीकडच्या Model view icon वर click करा.
- DarkStore मधला Store ID ओढून Orders मधल्या Store ID वर सोडा.
- Line वर double-click करा. तपासा: One to many, Single, Active.
- Report view मध्ये परत जा. Matrix आता बरोबर विभागतो.
- (Blank) row दिसली तर Orders मधले काही Store IDs DarkStore मध्ये नाहीत. Dimension fix करा.
एक-एक step करके देखिए:
- बाईं ओर के Model view icon पर click कीजिए.
- DarkStore का Store ID खींचकर Orders के Store ID पर छोड़िए.
- Line पर double-click कीजिए. जाँचिए: One to many, Single, Active.
- Report view में वापस जाइए. Matrix अब सही बँटता है.
- (Blank) row दिखे तो Orders के कुछ Store IDs DarkStore में नहीं हैं. Dimension fix कीजिए.
What you should see on screen after the steps (sample layout — fictional data, not a Microsoft screenshot).
Power BI often creates relationships automatically when column names and types match (autodetect). Always check them in Model view or Modeling › Manage relationships.
To create a relationship manually: in Model view, drag the key column from one table onto the matching column of another table, or use Manage relationships › New.
Cardinality
| Cardinality | Meaning | Example |
|---|---|---|
| One-to-many (1:*) | One row in the dimension relates to many rows in the fact | Product 1 → * Orders |
| Many-to-one (*:1) | Same many-to-one link as Product (one) to Orders (many), seen from the Orders side | Orders * → 1 Product |
| One-to-one (1:1) | Unique on both sides | Employee ↔ Employee Details (usually better merged into one table) |
| Many-to-many (*:*) | Neither column has unique values | Orders ↔ City Targets (targets per city per month, a different grain) – use carefully |
In the diagram, 1 and * labels appear at each end of the relationship line.
Cross-filter direction
- Single (default for 1:): filters flow from the one side (dimension) to the many* side (fact). Selecting "Snacks" in
Product[Category]filtersOrders. - Both (bi-directional): filters flow in both directions. Sometimes needed (e.g. to filter a slicer of customers to only those who bought), but it can cause ambiguity (संदिग्धता – एकापेक्षा जास्त अर्थ किंवा मार्ग), unexpected results and slower performance.
Avoid 'Both' unless you really need it
Prefer single direction. If you need bi-directional behaviour for one calculation, use DAX CROSSFILTER(…, Both) inside CALCULATE for just that measure instead of changing the relationship for the entire model. For slicers, a visual-level filter such as [Total Sales] is not blank often solves the need.
Active and inactive relationships
Mhanje asa: between two tables, only one relationship can be active at a time. In our sample, Orders has two dates – Order Date and Delivered Date – both related to Date[Date]. They usually match, pan an order placed at 11:55 pm may be delivered after midnight, on the next date:
Date[Date]→Orders[Order Date]is active (solid line). All visuals use it by default.Date[Date]→Orders[Delivered Date]is inactive (dotted line). It is used only when a measure activates it with USERELATIONSHIP:
Sales by Delivered Date =
CALCULATE(
[Total Sales],
USERELATIONSHIP(Orders[Delivered Date], 'Date'[Date])
)
Alternative approach: create a second date table (a role-playing dimension, e.g. Delivered Date) – but this increases model size.
Relationship properties dialog
Double-click a relationship line to open it. You can set these options:
- Cardinality: how many rows on each side match (one-to-many, one-to-one, many-to-many).
- Cross filter direction: which way filters flow.
- Make this relationship active.
- Apply security filter in both directions: for RLS with two-way filters.
- Assume referential integrity: DirectQuery only. It allows inner joins, so queries run faster.
Got it? The relationship direction goes from the dimension to the fact. If not, look at the diagram once more.
समजलं का? Relationship ची direction dimension कडून fact कडे. नसेल समजलं तर diagram पुन्हा एकदा बघा.
समझ आया? Relationship की direction dimension से fact की ओर. नहीं समझा तो diagram एक बार फिर देखिए.
Ravindra Bagale's Tip
A common mistake is ignoring the (Blank) row that appears in slicers and visuals. It means some keys in the fact table have no match in the dimension (for example a new Store ID missing from DarkStore). Fix the dimension or the key cleaning, rather than filtering (Blank) out and hiding the problem. Don't worry – after doing it two or three times, it becomes a habit.
Ravindra Bagale's Tip – मराठी
एक common चूक म्हणजे slicers आणि visuals मध्ये दिसणाऱ्या (Blank) row कडे दुर्लक्ष करणं. याचा अर्थ fact table मधल्या काही keys ना dimension मध्ये match नाही (उदाहरणार्थ DarkStore मध्ये नसलेला नवा Store ID). (Blank) filter करून problem लपवण्याऐवजी dimension किंवा key cleaning दुरुस्त करा. घाबरू नका, दोन-तीन वेळा केलं की सवय होते.
Ravindra Bagale's Tip – हिंदी
एक common गलती है slicers और visuals में दिखने वाली (Blank) row को नज़रअंदाज़ करना. इसका मतलब है fact table की कुछ keys का dimension में कोई match नहीं है (जैसे DarkStore में नहीं मौजूद नया Store ID). (Blank) को filter करके problem छिपाने की बजाय dimension या key cleaning ठीक करो. घबराओ मत, दो-तीन बार करने पर आदत हो जाती है.
Fix common mistakes
| Wrong result | Reason | Correction |
|---|---|---|
| Every row shows the grand total | No relationship, or the wrong columns related | Relate the key columns |
| A (Blank) row with an amount | An Orders Store value is missing in DarkStore (e.g. Kothrud with a space) |
Trim keys; add the missing store |
| Cannot create a one-to-many relationship | Duplicate keys in DarkStore | Remove duplicates or fix the key |
Practise independently
Practice task
Add a fictional order 309 with Store Wakad (not in DarkStore) and Amount ₹100. What does the City matrix show?
Hints
- Wakad has no City in the dimension.
Solution
A (Blank) row with ₹100; Pune ₹850, Nashik ₹800, Kolhapur ₹450; total ₹2,200. Fix: add Wakad to DarkStore.
Think like a professional
Every relationship needs a reason: key, cardinality, direction. Check for (Blank) rows after each refresh; they reveal missing dimension members.
Loading DAX practice tasks...
- Rows per Unit (Easy): Shown per Units Name. Measure: Row Count = number of Ledger rows.
- Revenue for Service only (Medium): Shown per City. Measure: Revenue Service = SUM of Revenue where Segment is "Service".
- Share of Revenue (Medium): Shown per Units Name. Measure: Revenue Share = SUM of Revenue ÷ SUM of Revenue for all of Units.
- How many units per Segment (Medium): Shown per Segment. Measure: Units Count = distinct count of UnitID in Ledger.
- Average receivables per country (Easy): Shown per Country. Measure: Avg Receivables = AVERAGE of Receivables.
- Cost Ratio (Medium): Shown per Units Name. Measure: Cost Ratio = SUM of Cost ÷ SUM of Revenue.
- Average Revenue per row (Medium): Shown per Units Name. Measure: Revenue per Row = SUM of Revenue ÷ number of rows.
- Rows with high receivables (Medium): Shown per Country. Measure: High Receivables Rows = number of rows where Receivables is more than 300000.
- Revenue in the first half-year (Medium): Shown per Country. Measure: H1 Revenue = SUM of Revenue for MonthDate before 1 Oct 2025.
- Rank by Revenue (Hard): Shown per Units Name. Measure: Revenue Rank = rank of [Total Revenue] among all Units Name values.
Revision card
Interview card