Ravindra BagaleCourses & study guides मराठी Track your progress

11. Data Modelling

11.4 Relationships in Power BI with Example: Cardinality and Direction

In short: A relationship tells Power BI which key column links two tables.

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

  1. Model view › drag DarkStore[Store] onto Orders[Store].
  2. 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
  3. Look at the matrix again.

    Your result should look like this:

    City Amount (₹)
    Kolhapur 450
    Nashik 800
    Pune 850
  4. 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.

First look at the data (before → after):

Relationships in Power BI with example (one-to-many): before and after tables, fictional Blinkit Maharashtra data

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:

  1. Click the Model view icon on the left.
  2. Drag Store ID from DarkStore and drop it on Store ID in Orders.
  3. Double-click the line. Check: One to many, Single, Active.
  4. Go back to Report view. The matrix now splits correctly.
  5. If you see a (Blank) row, some Orders Store IDs are missing from DarkStore. Fix the dimension.

What appears on screen after these steps — sample layout, fictional data

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] filters Orders.
  • 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:

  1. Cardinality: how many rows on each side match (one-to-many, one-to-one, many-to-many).
  2. Cross filter direction: which way filters flow.
  3. Make this relationship active.
  4. Apply security filter in both directions: for RLS with two-way filters.
  5. 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.

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.

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...

  1. Rows per Unit (Easy): Shown per Units Name. Measure: Row Count = number of Ledger rows.
  2. Revenue for Service only (Medium): Shown per City. Measure: Revenue Service = SUM of Revenue where Segment is "Service".
  3. Share of Revenue (Medium): Shown per Units Name. Measure: Revenue Share = SUM of Revenue ÷ SUM of Revenue for all of Units.
  4. How many units per Segment (Medium): Shown per Segment. Measure: Units Count = distinct count of UnitID in Ledger.
  5. Average receivables per country (Easy): Shown per Country. Measure: Avg Receivables = AVERAGE of Receivables.
  6. Cost Ratio (Medium): Shown per Units Name. Measure: Cost Ratio = SUM of Cost ÷ SUM of Revenue.
  7. Average Revenue per row (Medium): Shown per Units Name. Measure: Revenue per Row = SUM of Revenue ÷ number of rows.
  8. Rows with high receivables (Medium): Shown per Country. Measure: High Receivables Rows = number of rows where Receivables is more than 300000.
  9. Revenue in the first half-year (Medium): Shown per Country. Measure: H1 Revenue = SUM of Revenue for MonthDate before 1 Oct 2025.
  10. Rank by Revenue (Hard): Shown per Units Name. Measure: Revenue Rank = rank of [Total Revenue] among all Units Name values.

Ravi Sir's Cards for this lesson

मराठी cards