Power BI DAX Tutorial for Beginners

Learn what DAX (Data Analysis Expressions) is, why it matters, and create your first measure — the Vista way.

Beginner’s Guide to DAX Functions in Power BI — Vista Academy
Image: Beginner’s Guide to DAX Functions in Power BI

What is DAX?

DAX (Data Analysis Expressions) is the formula language of Power BI, used to build measures, calculated columns, and advanced analytics.

Power BI Excel Power Pivot SSAS Tabular

Why Learn DAX?

  • Create dynamic KPIs: Profit %, Growth %, Rank
  • Time Intelligence: MTD, QTD, YTD, LY
  • Granular control over filters & context
Jump to Quick Start →

Measure vs Column (Quick Rule)

Calculated Column → fixed per row (refresh time).
Measure → calculates on the fly (report filters).

Did you know? Power BI supports 250+ DAX functions. Start with core ones and level up to Time Intelligence and CALCULATE.

Quick Start: Your First DAX Measure

Create a basic KPI safely with DIVIDE to avoid divide-by-zero errors.

Profit % =
DIVIDE(
  SUM(Orders[Profit]),
  SUM(Orders[Sales]),
  0
)

Next: Learn logical bucketing with SWITCH(TRUE()) in our Next Steps.

Beginner Checklist ✅

  • Know your tables & relationships
  • Create your first Measure
  • Use DIVIDE instead of /
  • Practice IF and SWITCH
  • Try a simple YTD using DATESYTD
Text Functions
UPPER, PROPER, LEFT, RIGHT, MID, SUBSTITUTE — clean and transform names & labels.
Logical Functions
IF, SWITCH, AND, OR — classify, segment, and control results.
Time Intelligence
MTD, QTD, YTD, SAMEPERIODLASTYEAR, DATESINPERIOD — period-based insights.

Where to go next

  1. Read the full guide: DAX Functions in Power BI (Examples)
  2. Master logical decisions: IF & SWITCH with scenarios
  3. Level up with time intelligence: MTD / YTD / QTD / LY

DAX Tutorial in Power BI from Scratch

Load the Superstore table, build your Date table, and create your first measures.

Step 1 — Load Superstore Data

  1. Open Power BI Desktop.
  2. Home → Get DataWeb.
  3. Paste this link:
    📂 Open Superstore (Google Sheet)
  4. Select worksheet Superstore (or your Orders sheet) and click Load.

If access is restricted, publish to web or export CSV and use Get Data → Text/CSV.

Step 2 — Create a Date Table

Time intelligence needs a proper Date table.

Calendar =
ADDCOLUMNS(
    CALENDAR( MIN('Superstore'[Order Date]), MAX('Superstore'[Order Date]) ),
    "Year", YEAR([Date]),
    "MonthNum", MONTH([Date]),
    "MonthName", FORMAT([Date], "MMM"),
    "Quarter", "Q" & FORMAT([Date], "Q")
)

Model view → relate Calendar[Date]Superstore[Order Date] (Many-to-one, single).

Step 3 — Your First Measures

Modeling → New measure:

Total Sales  = SUM('Superstore'[Sales])
Total Profit = SUM('Superstore'[Profit])

Use these in Cards or a Matrix (e.g., by Region, Segment).

Next up: Text Functions in DAX, Logical Functions, and Time Intelligence (YTD/MTD/QTD) in dedicated sections.

Text Functions in Power BI DAX [Tutorial]

Clean, transform, and format text with DAX. All examples use the Superstore table. Need the data? Open Superstore Google Sheet →

Case Conversion

Customer Upper = UPPER('Superstore'[Customer Name])
Customer Lower = LOWER('Superstore'[Customer Name])
Customer Proper = PROPER('Superstore'[Customer Name])

Use PROPER for display, UPPER for grouping consistency.

Get Parts of Text

First 5   = LEFT('Superstore'[Customer Name], 5)
Last 3    = RIGHT('Superstore'[Customer Name], 3)
Middle    = MID('Superstore'[Product Name], 4, 3)
Name Len  = LEN('Superstore'[Customer Name])

LEFT/RIGHT are great for codes; MID helps with SKU parsing.

Join Text

Region Label = "Region: " & 'Superstore'[Region]

Products (as list) =
CONCATENATEX(
  VALUES('Superstore'[Product Name]),
  'Superstore'[Product Name],
  ", "
)

Use CONCATENATEX to roll up multiple rows into a single list.

Clean Spaces & Non-Printable

Customer Trimmed = TRIM('Superstore'[Customer Name])
Description Clean = CLEAN('Superstore'[Product Name])

Trim/Clean before matching or joining to avoid hidden-space issues.

Replace Text

Dash Region = SUBSTITUTE('Superstore'[Region], " ", "-")
Mask First3 = REPLACE('Superstore'[Customer Name], 1, 3, "***")

SUBSTITUTE targets substring values; REPLACE targets by position.

Format Numbers as Text

Sales Label = "₹ " & FORMAT('Superstore'[Sales], "#,##0")

Great for titles/tooltips. Note: FORMAT returns text, not numbers.

Find Text Position

Space Pos = SEARCH(" ", 'Superstore'[Customer Name], 1, -1)
Find BI   = FIND("BI", "Power BI")   -- case-sensitive

SEARCH is case-insensitive; FIND is case-sensitive.

Smart Text Checks

Has Tech = CONTAINSSTRING('Superstore'[Product Name], "Technology")
Starts An = STARTSWITH('Superstore'[Customer Name], "An")
Ends ra   = ENDSWITH('Superstore'[Customer Name], "ra")

Ideal for segmentation or conditional formatting.

Exact Match & Unicode

Is Exact = EXACT("Power BI", "power bi")   -- FALSE
Smiley   = UNICHAR(9786)
Code A   = UNICODE("A")   -- 65

Use EXACT for strict validation scenarios.

Roll Up Names into a List

Customers in Region =
CONCATENATEX(
  VALUES('Superstore'[Customer Name]),
  'Superstore'[Customer Name],
  ", ",
  'Superstore'[Customer Name],
  ASC
)

Place Region on rows, use this measure as value to see comma-lists per region.

Create Chip-Style Labels

Segment • Region =
'Superstore'[Segment] & " • " & 'Superstore'[Region]

Use in table cells or tooltips for compact descriptors.

Multi-line Labels (Cards/Table)

Customer Badge =
'Superstore'[Customer Name] & UNICHAR(10) &
"Region: " & 'Superstore'[Region]

Turn on Word wrap in the visual to display line breaks.

KPI Text (with FORMAT)

Total Sales  = SUM('Superstore'[Sales])
Total Profit = SUM('Superstore'[Profit])

KPI Label =
"Sales: ₹ " & FORMAT([Total Sales], "#,##0") & UNICHAR(10) &
"Profit: ₹ " & FORMAT([Total Profit], "#,##0")

Perfect for a two-line Card visual.

Logical Basic Functions in Power BI DAX

Learn to build rules and categories using IF, SWITCH, AND/OR/NOT, IN, ISBLANK, COALESCE, and more — with practical Superstore examples.

IF — Simple Rule

Classify each row (calculated column) or dynamic result (measure) based on a condition.

-- Calculated Column (row-by-row)
High Discount? = IF('Superstore'[Discount] >= 0.2, "High", "Normal")

-- Measure (dynamic, context aware)
Total Sales = SUM('Superstore'[Sales])
Sales Flag = IF([Total Sales] > 200000, "Target Met", "Below Target")

Use a column when the logic is fixed per row; use a measure when it must respond to filters.

IFERROR & DIVIDE — Safe Math

Avoid errors (e.g., division by zero) with IFERROR or DIVIDE.

Total Quantity = SUM('Superstore'[Quantity])
Total Profit   = SUM('Superstore'[Profit])

Profit per Unit (safe) =
DIVIDE([Total Profit], [Total Quantity], 0)

-- Equivalent with IFERROR (less preferred)
Profit per Unit (iferror) =
IFERROR([Total Profit] / [Total Quantity], 0)

Best practice: prefer DIVIDE for readability and built-in error handling.

SWITCH(TRUE()) — Range Buckets

Use SWITCH(TRUE()) to test multiple conditions in order.

Total Sales = SUM('Superstore'[Sales])

Sales Performance =
SWITCH(
  TRUE(),
  [Total Sales] > 500000, "Excellent",
  [Total Sales] > 200000, "Good",
  [Total Sales] > 100000, "Average",
  "Poor"
)

Order matters: the first TRUE condition returns the result.

SWITCH — Exact Mapping

Best for one-to-one label mapping.

Shipping Speed =
SWITCH(
  'Superstore'[Ship Mode],
  "Same Day",      "Instant",
  "First Class",   "Fast",
  "Second Class",  "Normal",
  "Standard Class","Slow",
  "Unknown"
)

Great for friendly labels in visuals or tooltips.

AND / OR / NOT

-- Row-level (calculated column)
Profitable & High Sales? =
IF( AND('Superstore'[Profit] > 0, 'Superstore'[Sales] > 500), TRUE(), FALSE() )

-- Measure-level (context aware)
High Margin or High Sales =
IF( OR([Total Profit] > 80000, [Total Sales] > 300000), "Yes", "No")

Use AND/OR for compound rules; NOT to invert a condition.

IN — Membership Test

Focus Regions =
IF( 'Superstore'[Region] IN {"East","West"}, "Focus", "Other" )

Cleaner than chaining multiple OR conditions.

TRUE() / FALSE()

Always True  = TRUE()
Always False = FALSE()

Useful for default states or debugging filters.

ISBLANK / COALESCE

Handle missing values gracefully.

Avg Discount = AVERAGE('Superstore'[Discount])

Avg Discount (no blank) =
COALESCE([Avg Discount], 0)

Discount Label =
IF( ISBLANK([Avg Discount]), "No Data", FORMAT([Avg Discount], "0.0%") )

COALESCE returns the first non-blank — simpler than nested IFs.

Show/Hide with BLANK()

Return BLANK() to hide values in visuals.

Total Profit = SUM('Superstore'[Profit])

Profit (hide negative) =
IF([Total Profit] < 0, BLANK(), [Total Profit])

Great for decluttering charts with negative outliers.

CONTAINSSTRING / STARTSWITH / ENDSWITH

Create segments from names and categories.

Tech Product? =
IF( CONTAINSSTRING('Superstore'[Category], "Technology"), TRUE(), FALSE() )

Starts with A? =
STARTSWITH('Superstore'[Customer Name], "A")

Ends with ra? =
ENDSWITH('Superstore'[Customer Name], "ra")

Use these in filters/conditional formatting for instant segmentation.

Combine Logic for Badges

Total Sales = SUM('Superstore'[Sales])
Total Profit = SUM('Superstore'[Profit])

Account Badge =
SWITCH(
  TRUE(),
  AND([Total Sales] > 300000, [Total Profit] > 60000), "⭐ Key Account",
  [Total Sales] > 150000, "Growth",
  [Total Profit] < 0, "At Risk",
  "Regular"
)

Drop this in a table alongside Customer/Region to highlight focus accounts.

How to Convert a Column and Measure into Power BI DAX

Understand when to use a Calculated Column vs a Measure, how to “convert” logic between them, and common pitfalls. Examples use Superstore. Need data? Open Superstore Sheet →

Golden Rule (When to use what?)

  • Calculated Column → Row-by-row, computed at refresh, stored in the model (increases size). Good for grouping, slicers, relationships.
  • Measure → Calculated on the fly, respects filters/context, lightweight. Good for KPIs, cards, charts, tooltips.

A) Convert Column-style Logic → Measure

If you had a calculated column per row, you can aggregate its logic in a measure.

Original (Calculated Column): “High Discount?”

High Discount? =
IF('Superstore'[Discount] >= 0.20, "High", "Normal")

Converted (Measure): % of rows with High Discount under current filters

High Discount Rows =
CALCULATE(
  COUNTROWS('Superstore'),
  'Superstore'[Discount] >= 0.20
)

Total Rows =
COUNTROWS('Superstore')

% High Discount =
DIVIDE([High Discount Rows], [Total Rows], 0)

Now the result changes with slicers (Region, Segment, Date).

B) Convert Measure-style Logic → Column (when possible)

Pure measure logic depends on filter context; it often cannot be “stored” per row. But you can create an equivalent column using row-level data.

Original (Measure): Profit %

Total Profit = SUM('Superstore'[Profit])
Total Sales  = SUM('Superstore'[Sales])

Profit % =
DIVIDE([Total Profit], [Total Sales], 0)

Row-level approximation (Calculated Column):

Row Profit % =
DIVIDE('Superstore'[Profit], 'Superstore'[Sales], 0)

This gives a row’s margin, not the dynamic total margin. For visuals, the measure version is the correct KPI.

Pattern 1 — Replace Row Flags with Dynamic Segments

Instead of storing many flag columns, use a segmenting measure.

Total Sales = SUM('Superstore'[Sales])
Account Segment =
SWITCH(
  TRUE(),
  [Total Sales] > 300000, "⭐ Key",
  [Total Sales] > 150000, "Growth",
  [Total Sales] >  50000, "Emerging",
  "New"
)

Use in a slicer or legend — it reacts to filters (Year, Region).

Pattern 2 — Turn a Column into a Lookup/Grouping

Create a small table for categories; use it in slicers without bloating your fact table.

Segments =
DATATABLE(
  "Segment", STRING,
  { {"Consumer"}, {"Corporate"}, {"Home Office"} }
)

Relate to ‘Superstore’ or use in disconnected slicers with measures.

Pattern 3 — Show/Hide with BLANK() Instead of a Column

Avoid adding a column to filter visibility; let the measure return nothing.

Total Profit = SUM('Superstore'[Profit])
Profit (hide negative) =
IF([Total Profit] < 0, BLANK(), [Total Profit])

Visuals skip BLANK values — cleaner charts, simpler model.

Hands-On Checklist

  1. Create a column: High Discount? = IF('Superstore'[Discount] >= 0.20, "High","Normal")
  2. Create a measure set: Total Rows, High Discount Rows, % High Discount
  3. Build a Matrix: Rows = Region, Values = % High Discount
  4. Add slicers (Year, Segment) and watch the measure update dynamically.

FAQ: Can I convert any Measure to a Column?

Not always. Measures depend on filter context (report-time). A column must be computed per row at refresh. If your logic aggregates (SUM, AVERAGE), keep it as a measure.

Performance Tip

Avoid many boolean flag columns. Prefer segmentation measures (using SWITCH(TRUE())) — smaller models, more flexibility.

CALCULATE Function in Power BI DAX

CALCULATE is the most powerful and important DAX function. It changes the filter context and lets you apply custom filters to calculations. All examples below use the Superstore dataset. Need data? Open Superstore Sheet →

Syntax

CALCULATE(<expression>, <filter1>, <filter2>, ...)
  • <expression> → the measure or aggregation you want (e.g., SUM, AVERAGE).
  • <filters> → conditions that modify the filter context.

Example 1 — Sales in a Region

Total Sales = SUM('Superstore'[Sales])

Sales East =
CALCULATE(
  [Total Sales],
  'Superstore'[Region] = "East"
)

Always returns sales for the East region, regardless of slicers.

Example 2 — Sales Above Threshold

High Value Sales =
CALCULATE(
  SUM('Superstore'[Sales]),
  'Superstore'[Sales] > 1000
)

Counts only transactions with sales over ₹1000.

Example 3 — Filter by Category

Furniture Sales =
CALCULATE(
  [Total Sales],
  'Superstore'[Category] = "Furniture"
)

Ignores slicer filters and only shows Furniture sales.

Example 4 — Multiple Conditions

East Furniture Sales =
CALCULATE(
  [Total Sales],
  'Superstore'[Region] = "East",
  'Superstore'[Category] = "Furniture"
)

Applies multiple filters in one formula.

Advanced Example — CALCULATE with Time Intelligence

Total Sales = SUM('Superstore'[Sales])

Sales Last Year =
CALCULATE(
  [Total Sales],
  SAMEPERIODLASTYEAR('Calendar'[Date])
)

Combines CALCULATE with SAMEPERIODLASTYEAR to show year-over-year comparisons.

Why CALCULATE is Special?

  • Changes the filter context dynamically
  • Works with measures, filters, time intelligence
  • Foundation for most advanced DAX patterns

Common Mistakes

  • Forgetting to create a proper Calendar table
  • Mixing row context vs filter context
  • Using columns instead of measures where aggregation is needed

Power BI DAX Time Intelligence Formula

Build calendar-aware KPIs like MTD, QTD, YTD, Prior Year, YoY%, and Rolling periods using Time Intelligence functions. Examples use Superstore with a proper Calendar table.

Prerequisites (Do this once)

  1. Create a Calendar table that spans your data range:
    Calendar =
    ADDCOLUMNS(
      CALENDAR( MIN('Superstore'[Order Date]), MAX('Superstore'[Order Date]) ),
      "Year", YEAR([Date]),
      "MonthNum", MONTH([Date]),
      "MonthName", FORMAT([Date], "MMM"),
      "Quarter", "Q" & FORMAT([Date], "Q")
    )
  2. Model view → relate Calendar[Date]Superstore[Order Date] (Many-to-one, single direction).
  3. Table tools → Mark as date table with column Calendar[Date].

Base Measures

Total Sales  = SUM('Superstore'[Sales])
Total Profit = SUM('Superstore'[Profit])

We’ll reference these in MTD/QTD/YTD and other formulas.

Quick Tip

Put Calendar[Year] and Calendar[MonthName] on the axis of visuals. Time Intelligence works best with fields from the Calendar table.

Month-To-Date (MTD)

Sales MTD =
CALCULATE(
  [Total Sales],
  DATESMTD('Calendar'[Date])
)

Respects current filter (e.g., a selected month/year).

Quarter-To-Date (QTD)

Sales QTD =
CALCULATE(
  [Total Sales],
  DATESQTD('Calendar'[Date])
)

Accumulates from quarter start to the current date in context.

Year-To-Date (YTD)

Sales YTD =
CALCULATE(
  [Total Sales],
  DATESYTD('Calendar'[Date])
)

Default year-end is Dec 31. For fiscal years, use DATESYTD('Calendar'[Date], "06/30").

Same Period Last Year (PY)

Sales PY =
CALCULATE(
  [Total Sales],
  SAMEPERIODLASTYEAR('Calendar'[Date])
)

Compares current context (month/quarter/YTD) with the same period last year.

Year-over-Year % (YoY%)

YoY % =
VAR Prev = [Sales PY]
RETURN DIVIDE( [Total Sales] - Prev, Prev, 0 )

Place alongside Total Sales for growth analysis.

Month-over-Month Change

Sales Prev Month =
CALCULATE(
  [Total Sales],
  DATEADD('Calendar'[Date], -1, MONTH)
)

MoM % = DIVIDE( [Total Sales] - [Sales Prev Month], [Sales Prev Month], 0 )

Use Calendar[Year] & Calendar[MonthName] on axis for clarity.

Rolling 3 Months (R3M)

Sales R3M =
CALCULATE(
  [Total Sales],
  DATESINPERIOD('Calendar'[Date], MAX('Calendar'[Date]), -3, MONTH)
)

Smooths short-term fluctuations; works with any period length.

Rolling 12 Months (R12M)

Sales R12M =
CALCULATE(
  [Total Sales],
  DATESINPERIOD('Calendar'[Date], MAX('Calendar'[Date]), -12, MONTH)
)

Great for trend dashboards and seasonality insights.

Visualization Tips

  • Line/Area charts: Axis = Calendar[Date] or Year→MonthName; Values = Total Sales, Sales PY, Sales MTD/YTD.
  • Cards: show YTD, PY, and YoY% together.
  • Matrix: Rows = Region/Segment; Values = YTD, YoY% for comparative views.

Power BI DAX: LOOKUPVALUE Function

Use LOOKUPVALUE() to fetch a value from another table without needing a relationship. It’s perfect when you can’t model a relation, or you’re doing a one-off enrichment.
Dataset: Open the Google Sheet Demo →

Syntax

LOOKUPVALUE(
  <result_column>,
  <search_column1>, <search_value1>,
  [<search_column2>, <search_value2>], ...,
  [<alternateResult>]
)
  • Returns a single value from <result_column> where all search pairs match.
  • If no match → returns BLANK() unless you provide alternateResult.
  • If multiple matches → throws an error (ensure keys are unique or add more search pairs).

2) When to Prefer LOOKUPVALUE vs RELATED

  • Use RELATED → when a relationship exists (faster, cleaner).
  • Use LOOKUPVALUE → when no relationship, or it’s impractical to create one, or keys live in a disconnected table.
  • If duplicates cause errors, fix keys or add more search pairs.

Example 1 — Single Key Lookup

Bring Region into FactSales based on Customer ID (no relationship needed).

-- Calculated Column in FactSales
Region via Lookup =
LOOKUPVALUE(
  DimCustomer[Region],
  DimCustomer[Customer ID], FactSales[Customer ID],
  "Unknown Region"   -- alternateResult (optional)
)

If a customer isn’t in DimCustomer, returns “Unknown Region”.

Example 2 — Multiple Key Lookup

Disambiguate duplicates: match both Product ID and Product Name.

-- Calculated Column in FactSales
SubCategory via Lookup =
LOOKUPVALUE(
  DimProduct[Sub-Category],
  DimProduct[Product ID],   FactSales[Product ID],
  DimProduct[Product Name], RELATED(DimProduct[Product Name]),  -- if relationship exists use the same value, else use Fact column
  "Unknown Sub-Category"
)

Add more search pairs to force a single match and avoid the “multiple values” error.

Example 3 — Use LOOKUPVALUE in a Measure

Map a selected Product ID from a slicer (disconnected table) to a label.

Selected Product Name =
VAR selPID =
    SELECTEDVALUE('SlicerProducts'[Product ID])
RETURN
LOOKUPVALUE(
  DimProduct[Product Name],
  DimProduct[Product ID], selPID,
  "No Product Selected"
)

Great for dynamic titles/cards using disconnected slicers.

Example 4 — Reverse Lookup (Find ID by Name)

Fetch a Customer ID when you only have the name.

Customer ID by Name =
LOOKUPVALUE(
  DimCustomer[Customer ID],
  DimCustomer[Customer Name], "Aarav Singh",
  BLANK()
)

Replace the hard-coded name with a field or parameter for dynamic behavior.

Troubleshooting & Best Practices

  • Multiple values error? Ensure the search columns are unique in the lookup table or add extra search pairs.
  • No match? Provide an alternateResult like "Unknown" to avoid BLANKs in visuals.
  • Performance: Prefer RELATED when a relationship is possible. Use LOOKUPVALUE for exceptions or disconnected mappings.
  • Columns vs Measures: Calculated columns store a value per row; measures compute on the fly. Choose based on your use case.

Power BI DAX Tutorial: Using KEEPFILTERS for Advanced Data Analysis

KEEPFILTERS() lets you add filters inside CALCULATE without wiping out the filters already applied by slicers or visuals. Data source: Superstore Google Sheet →

Why KEEPFILTERS?

  • CALCULATE([Measure], 'Table'[Column] = "X") normally replaces the filter on that column.
  • CALCULATE([Measure], KEEPFILTERS('Table'[Column] = "X")) will add the filter, intersecting with what’s already selected.
  • Perfect for layering criteria: e.g., users pick Category=Technology and you add Region=East inside the measure.

1) Load the Superstore Data

  1. Power BI Desktop → Home → Get Data → Web.
  2. Paste:
  3. Select the worksheet that contains your orders data (often named Superstore / Orders) and click Load.

Optional (recommended): add a Calendar table and relate Calendar[Date]Superstore[Order Date].

2) Base Measures

Total Sales  = SUM('Superstore'[Sales])
Total Profit = SUM('Superstore'[Profit])

We’ll layer KEEPFILTERS on top of these.

Example 1 — Layering Category with User Slicers

User picks a Region in a slicer. You want Technology sales but keep the Region selection.

Tech Sales (keep slicers) =
CALCULATE(
  [Total Sales],
  KEEPFILTERS('Superstore'[Category] = "Technology")
)

Any Region/Segment/Date filter from visuals remains intact; we just add Category=Technology.

Example 2 — Numeric Condition with KEEPFILTERS

Keep user choices but count only high-value orders (Sales ≥ ₹10,000).

High Value Sales =
CALCULATE(
  SUM('Superstore'[Sales]),
  KEEPFILTERS('Superstore'[Sales] >= 10000)
)

Filters on Region/Date/Segment continue to apply; this adds an amount threshold.

Example 3 — Multiple Intersecting Filters

Add Category=Furniture and Ship Mode=First Class while preserving slicers.

Furniture FirstClass Sales =
CALCULATE(
  [Total Sales],
  KEEPFILTERS('Superstore'[Category] = "Furniture"),
  KEEPFILTERS('Superstore'[Ship Mode] = "First Class")
)

Behaves like AND logic with whatever slicers are already filtering the report.

Example 4 — With Time Intelligence

Keep current Year/Month selections, then add a sub-filter like Sub-Category=Machines.

Sales YTD • Machines =
CALCULATE(
  [Total Sales],
  DATESYTD('Calendar'[Date]),
  KEEPFILTERS('Superstore'[Sub-Category] = "Machines")
)

Layer period logic with product filtering without breaking user selections.

KEEPFILTERS vs Plain CALCULATE Filter

-- If a slicer sets Category = "Technology"
-- This IGNORES that and forces Furniture (replaces filter)
Furniture (replace) =
CALCULATE([Total Sales], 'Superstore'[Category] = "Furniture")

-- This KEEPS slicer filters AND adds Furniture (usually results in blank unless both intersect)
Furniture (keep) =
CALCULATE([Total Sales], KEEPFILTERS('Superstore'[Category] = "Furniture"))

If the intersection is empty (Tech ∩ Furniture), result is BLANK — that’s expected and often desired.

KEEPFILTERS vs REMOVEFILTERS

-- REMOVEFILTERS clears context first, then your filters apply
Furniture (clear-then-apply) =
CALCULATE(
  [Total Sales],
  REMOVEFILTERS('Superstore'[Category]),
  'Superstore'[Category] = "Furniture"
)

KEEPFILTERS = intersect with existing filters. REMOVEFILTERS = wipe filters, then apply your own.

Quick Visual Recipe

  1. Add slicers for Region, Segment, and Category.
  2. Create measures Tech Sales (keep slicers) and Furniture FirstClass Sales.
  3. Use a Matrix: Rows = Region, Columns = Category, Values = your KEEPFILTERS measures.
  4. Play with slicers: the measures remain constrained by the slicers and the extra KEEPFILTERS criteria.

Power BI DAX Tutorial: Using REMOVEFILTERS for Advanced Data Analysis

REMOVEFILTERS() clears filters from a column or table inside CALCULATE so you can compute totals, baselines, and % of total — regardless of slicers or row/column context. Dataset: Superstore Google Sheet →

1) Load Data & Base Measures

  1. Power BI → Get Data → Web → paste the Google Sheet link above.
  2. Select the orders worksheet (often named Superstore) and click Load.
  3. (Recommended) Create a Calendar table and relate Calendar[Date]Superstore[Order Date].
Total Sales  = SUM('Superstore'[Sales])
Total Profit = SUM('Superstore'[Profit])

When to use REMOVEFILTERS?

  • Compute grand totals ignoring current slicers (e.g., % of overall sales).
  • Build benchmarks (total this year vs selected sub-slice).
  • Do context transitions where you must reset one column/table’s filter.

Pattern 1 — % of Total (Ignore Category filter)

Show each category’s % of all categories even when a Category slicer is used.

All-Category Sales =
CALCULATE(
  [Total Sales],
  REMOVEFILTERS('Superstore'[Category])          -- clears only Category filter
)

Category % of All =
DIVIDE([Total Sales], [All-Category Sales], 0)

Use in a matrix: Rows = Category, Values = Total Sales, Category % of All.

Pattern 2 — % of Grand Total (Ignore ALL filters)

Completely ignore slicers (Region, Segment, Date…) to get a true grand total baseline.

Grand Total Sales =
CALCULATE(
  [Total Sales],
  REMOVEFILTERS('Superstore')                    -- clears all filters from Superstore
)

% of Grand Total =
DIVIDE([Total Sales], [Grand Total Sales], 0)

Ideal for global % KPIs, regardless of user selections.

Pattern 3 — Fixed Baseline with Time Intelligence

Compare current selection to the entire year regardless of other filters.

Sales YTD (Selected) =
CALCULATE([Total Sales], DATESYTD('Calendar'[Date]))

Sales YTD (All Segments) =
CALCULATE(
  [Total Sales],
  DATESYTD('Calendar'[Date]),
  REMOVEFILTERS('Superstore'[Segment])           -- clears Segment only
)

Selected vs All Segments % =
DIVIDE([Sales YTD (Selected)] - [Sales YTD (All Segments)], [Sales YTD (All Segments)], 0)

Use Year/Month from Calendar on the axis.

Pattern 4 — Clear then Apply Specific Filter

Classic pattern to avoid conflicting filters.

Furniture Sales (clear-then-apply) =
CALCULATE(
  [Total Sales],
  REMOVEFILTERS('Superstore'[Category]),         -- wipe Category filters
  'Superstore'[Category] = "Furniture"           -- then apply Furniture
)

Ensures the measure reflects exactly the chosen category, ignoring slicers for Category only.

REMOVEFILTERS vs ALL

-- Nearly equivalent inside CALCULATE:
CALCULATE([Total Sales], REMOVEFILTERS('Superstore'[Category]))
CALCULATE([Total Sales], ALL('Superstore'[Category]))

Both clear filters. REMOVEFILTERS is a newer, explicit form.

ALLEXCEPT — Keep Some Filters

-- Clear all filters on table except those columns
Sales by Region (ignore others) =
CALCULATE(
  [Total Sales],
  ALLEXCEPT('Superstore', 'Superstore'[Region])
)

Keeps Region context but clears Category/Segment/…

KEEPFILTERS — Intersect with Existing

Tech Sales (keep) =
CALCULATE(
  [Total Sales],
  KEEPFILTERS('Superstore'[Category] = "Technology")
)

Adds filters instead of clearing them — opposite intent to REMOVEFILTERS.

Quick Visual Recipe

  1. Add slicers for Region, Segment, and Category.
  2. Create measures: All-Category Sales, Category % of All, % of Grand Total.
  3. Matrix: Rows = Category; Values = Total Sales, Category % of All, % of Grand Total.
  4. Interact with slicers to see how REMOVEFILTERS stabilizes baselines.

Power BI DAX Tutorial: Using SUMMARIZE Function

Group rows and build virtual tables for measures with SUMMARIZE(). Dataset: Superstore Google Sheet →

1) Load Data & Base Measures

  1. Power BI → Get Data → Web → paste the Superstore link above.
  2. Select your orders worksheet (Superstore/Orders) and click Load.
  3. (Recommended) Add a Calendar table and relate Calendar[Date]Superstore[Order Date].
Total Sales  = SUM('Superstore'[Sales])
Total Profit = SUM('Superstore'[Profit])

2) When to use SUMMARIZE?

  • Create a grouped virtual table inside a measure for further calculations (TOP-N, rankings, rollups).
  • Build calculated tables for reusable groups (e.g., sales by Region & Category).
  • Prefer SUMMARIZECOLUMNS inside measures (it handles filter context more naturally); use SUMMARIZE when you need legacy syntax or add row-context columns.

Pattern 1 — Basic Grouping

Sales by Region and Category as a calculated table.

Sales by Region & Category =
SUMMARIZE(
  'Superstore',
  'Superstore'[Region],
  'Superstore'[Category],
  "Total Sales", SUM('Superstore'[Sales]),
  "Total Profit", SUM('Superstore'[Profit])
)

Use this table in visuals or as a source for further modeling.

Pattern 2 — Virtual Table in a Measure

Compute Top 3 Categories by Sales under current filters.

Top 3 Category Sales =
VAR t =
    SUMMARIZE(
        'Superstore',
        'Superstore'[Category],
        "Cat Sales", [Total Sales]
    )
VAR top3 =
    TOPN(3, t, [Cat Sales], DESC)
RETURN
SUMX(top3, [Cat Sales])

Place on a Card; it reacts to slicers (Region/Date/Segment).

Pattern 3 — Rank Products by Profit within Category

Product Profit Rank =
VAR t =
    SUMMARIZE(
      'Superstore',
      'Superstore'[Category],
      'Superstore'[Product Name],
      "Total Profit", [Total Profit]
    )
RETURN
RANKX(
  FILTER(t, [Category] = SELECTEDVALUE('Superstore'[Category])),
  [Total Profit],
  ,
  DESC,
  Dense
)

Use Category as slicer to see rankings update.

Pattern 4 — Distinct Customers by Region + % of Total

Customers per Region =
VAR t =
    SUMMARIZE(
      'Superstore',
      'Superstore'[Region],
      "Cust Count", DISTINCTCOUNT('Superstore'[Customer ID])
    )
VAR total = SUMX(t, [Cust Count])
RETURN
DIVIDE(
  CALCULATE([Cust Count], KEEPFILTERS(VALUES('Superstore'[Region]))),
  total,
  0
)

Drop Region on rows and show this measure to see each region’s share.

Use SUMMARIZECOLUMNS inside Measures

-- Similar to Pattern 2 but with SUMMARIZECOLUMNS (respects filter context by default)
Top 3 Category Sales (Columns) =
VAR t =
  SUMMARIZECOLUMNS(
    'Superstore'[Category],
    "Cat Sales", [Total Sales]
  )
VAR top3 = TOPN(3, t, [Cat Sales], DESC)
RETURN SUMX(top3, [Cat Sales])

Cleaner for measure logic; no source table argument needed.

Add Calculated Expressions to Groups

Category Table with Margin =
ADDCOLUMNS(
  SUMMARIZE('Superstore', 'Superstore'[Category]),
  "Sales", [Total Sales],
  "Profit", [Total Profit],
  "Margin %", DIVIDE([Total Profit], [Total Sales], 0)
)

`ADDCOLUMNS` lets you compute measures per grouped row.

When to use GROUPBY

-- GROUPBY requires iterator expressions (X functions)
Sales by Region (GROUPBY) =
GROUPBY(
  'Superstore',
  'Superstore'[Region],
  "Sales", SUMX(CURRENTGROUP(), 'Superstore'[Sales])
)

Use when you need CURRENTGROUP() for custom aggregations.

Common Pitfalls & Tips

  • Filter vs Row Context: `SUMMARIZE` runs in filter context; measures used within must be context-safe. Prefer variables to capture measures first.
  • Blank rows: Intersections that don’t exist will return blank — expected behavior for inner joins.
  • Performance: For measure logic, SUMMARIZECOLUMNS is often more efficient and readable.
  • Materialize or not? Use a calculated table if you reuse the grouping across pages; otherwise keep it virtual inside measures.
  • Totals: Wrap final expressions with COALESCE/DIVIDE to avoid empty totals.

Quick Visual Recipe

  1. Matrix: Rows = Category, Columns = Region, Values = Total Sales, Total Profit.
  2. Card: Top 3 Category Sales measure (Pattern 2).
  3. Table: Use Category Table with Margin (ADDCOLUMNS) as source for a simple table visual.

One-File Demo: SalesOrders + Customers (Google Sheet)

Use a single file to learn SUMMARIZE, SUMMARIZECOLUMNS, and set-ops (UNION, EXCEPT, INTERSECT) without the noise of a big dataset.
Dataset link: Open the One-File Google Sheet →

Step 1 — Load the Google Sheet into Power BI

  1. Open Power BI DesktopHome → Get Data → Web.
  2. Paste the link above and click OK. Choose the sheet that contains the combined data (column Table shows “SalesOrders” or “Customers”).
  3. If your org blocks direct access, use one of these alternatives:
    • Download the sheet as Excel (File → Download → Microsoft Excel) → Get Data → Excel.
    • Publish to web (File → Share → Publish to web) to get a CSV link → Get Data → Web with that CSV URL.

Step 2 — Split into Two Queries (Power Query)

  1. With the table selected → Transform Data (Power Query).
  2. Duplicate the query (right-click the query name) twice and rename:
    SalesOrdersCustomers
  3. In SalesOrders: Filter column Table = "SalesOrders". Remove the Table column.
  4. In Customers: Filter column Table = "Customers". Remove the Table column.
  5. Set data types:
    SalesOrders → OrderID = Whole number, Sales = Whole number/decimal, Region/Category = Text.
    Customers → CustomerID = Whole number, Region/Segment = Text.
  6. Click Close & Apply.

Step 3 — Relationship (optional but useful)

Create a simple lookup so you can use Segment by Region with orders.

  1. Model view → drag Customers[Region]SalesOrders[Region].
  2. Cardinality: One-to-Many (Customers = one side, SalesOrders = many). Cross-filter: single.

Now you can filter orders by the Customers table’s Region/Segment.

Step 4 — Base Measures

Total Sales = SUM('SalesOrders'[Sales])

We’ll reuse [Total Sales] in all examples below.

Step 5A — SUMMARIZE (Calculated Table)

Group Sales by Region & Category and materialize a small table:

Sales by Region & Category =
SUMMARIZE(
  'SalesOrders',
  'SalesOrders'[Region],
  'SalesOrders'[Category],
  "Total Sales", [Total Sales]
)

Use this table directly in a Table visual, or as a source for further modeling.

Step 5B — SUMMARIZECOLUMNS (Virtual Table in a Measure)

Compute Top 2 Regions by Sales under current slicers:

Top 2 Region Sales =
VAR t =
  SUMMARIZECOLUMNS(
    'SalesOrders'[Region],
    "Reg Sales", [Total Sales]
  )
VAR top2 = TOPN(2, t, [Reg Sales], DESC)
RETURN SUMX(top2, [Reg Sales])

Drop on a Card; change slicers to see it update.

Step 6 — ADDCOLUMNS over Group (Dynamic)

Build a grouped table on Category and compute dynamic expressions per row:

Category Table =
ADDCOLUMNS(
  SUMMARIZE('SalesOrders', 'SalesOrders'[Category]),
  "Sales", [Total Sales]
)

Use this as a source for a simple Table visual to compare Category totals.

Step 7A — INTERSECT (Common Regions)

Regions with Orders = VALUES('SalesOrders'[Region])
Regions with Customers = VALUES('Customers'[Region])

Common Regions =
INTERSECT( Regions with Orders, Regions with Customers )

Calculated tables → show as separate tables to explain overlaps.

Step 7B — EXCEPT (New vs. Lost)

New Regions =
EXCEPT( Regions with Orders, Regions with Customers )

Lost Regions =
EXCEPT( Regions with Customers, Regions with Orders )

Explains “where we sell but have no customers yet” vs the opposite.

Step 7C — UNION (Combined Regions)

All Regions (Union) =
UNION( Regions with Orders, Regions with Customers )

Use for quick reference lists or slicers.

Step 8 — Quick Visual Recipe

  1. Matrix: Rows = Region; Columns = Category; Values = [Total Sales].
  2. Card: [Top 2 Region Sales].
  3. Table: Source = Category Table (from Step 6).
  4. Tables: Show Common Regions, New Regions, Lost Regions side-by-side to teach set logic.

Troubleshooting

  • Web import fails? Download as Excel/CSV and use Get Data → Excel or Text/CSV.
  • Set operations empty? Check exact text values of Region (“East”, “West”, “South”, “Central”).
  • Measure returns blank? Ensure you placed the right fields on the visual (e.g., Region/Category for grouped measures).
Venn Diagrams of INTERSECT, UNION, EXCEPT

Figure: Venn representations of DAX set operations — INTERSECT, UNION, EXCEPT.

INTERSECT (Common Regions)

Regions with Orders   = VALUES('SalesOrders'[Region])
Regions with Customers = VALUES('Customers'[Region])

Common Regions =
INTERSECT(
  Regions with Orders,
  Regions with Customers
)

Gives you only the regions present in both tables.

EXCEPT (New / Lost Regions)

New Regions =
EXCEPT(
  Regions with Orders,
  Regions with Customers
)

Lost Regions =
EXCEPT(
  Regions with Customers,
  Regions with Orders
)

Find regions with orders but no customers, and vice versa.

UNION (All Regions)

All Regions (Union) =
UNION(
  Regions with Orders,
  Regions with Customers
)

Creates a full list of unique regions from both tables.

Power BI Tutorial: Using the DISTINCT Function for Advanced Data Analysis

DISTINCT() returns a one-column table with unique values from a column, perfect for creating slicers, validating duplicates, or calculating distinct counts. Dataset: Superstore Google Sheet →

1) Create a Table of Unique Regions

Unique Regions =
DISTINCT('Superstore'[Region])

This calculated table lists each Region only once (East, West, Central, South). Useful for disconnected slicers or validation.

2A) Distinct Customers Count

Distinct Customers =
COUNTROWS(
    DISTINCT('Superstore'[Customer Name])
)

Counts the unique customers in the dataset. Similar to DISTINCTCOUNT(), but more flexible in advanced scenarios.

2B) Distinct Product Categories

Distinct Categories =
COUNTROWS(
    DISTINCT('Superstore'[Category])
)

Returns how many unique Categories exist in Superstore (Furniture, Technology, Office Supplies).

3) DISTINCT vs VALUES

  • DISTINCT(column) → Always returns unique values from the column, ignoring BLANKS.
  • VALUES(column) → Returns unique values and respects current filter context. Can include BLANK.
  • Use DISTINCT for raw uniqueness; use VALUES when working with slicers and current context.
Regions (Values) =
VALUES('Superstore'[Region])

Try placing both DISTINCT and VALUES in a Table visual with slicers to see the difference in behavior.

4) Quick Visual Recipe

  1. Create a Table visual: Values = Unique Regions table → shows 4 rows.
  2. Create a Card visual: Value = [Distinct Customers].
  3. Create another Card visual: Value = [Distinct Categories].
  4. Add slicers (Region, Category) and compare results of DISTINCT vs VALUES.

Mastering DAX: Unleash the Power of CALCULATE vs CALCULATETABLE in Power BI

Both functions **modify filter context**. The key difference: CALCULATE returns a scalar (number), while CALCULATETABLE returns a table you can iterate (e.g., with SUMX, COUNTROWS). Dataset: Superstore (see DISTINCT section) • See also: CALCULATE basics, SUMMARIZE, KEEPFILTERS, REMOVEFILTERS.

CALCULATE — Scalar Result

CALCULATE(<expression>, <filters...>)

Use for KPIs, cards, line/bar values.

CALCULATETABLE — Table Result

CALCULATETABLE(<table expression>, <filters...>)

Use for virtual tables → iterate with SUMX/TOPN/COUNTROWS or materialize as calculated tables.

Base Measures (Superstore)

Total Sales  = SUM('Superstore'[Sales])
Total Profit = SUM('Superstore'[Profit])

A) CALCULATE — Filtered KPIs

Furniture Sales =
CALCULATE(
  [Total Sales],
  'Superstore'[Category] = "Furniture"
)

East • Tech Profit =
CALCULATE(
  [Total Profit],
  'Superstore'[Region] = "East",
  'Superstore'[Category] = "Technology"
)

Returns a single value each → perfect for Cards/Tooltips.

B) CALCULATETABLE — Build Virtual Tables

-- 1) Orders table for Furniture only (virtual)
Furniture Orders (table) =
CALCULATETABLE(
  'Superstore',
  'Superstore'[Category] = "Furniture"
)

-- 2) Iterate over that table
Furniture Order Count =
COUNTROWS( Furniture Orders (table) )

Furniture Sales via SUMX =
SUMX( Furniture Orders (table), 'Superstore'[Sales] )

Use the table result in COUNTROWS/SUMX to build advanced measures.

C) Top-N with CALCULATETABLE + TOPN

Top 3 Products by Sales =
VAR t =
  CALCULATETABLE(
    SUMMARIZE('Superstore', 'Superstore'[Product Name],
              "Prod Sales", [Total Sales])
  )
VAR top3 = TOPN(3, t, [Prod Sales], DESC)
RETURN top3  -- return a table (use in a calculated table) 

Materialize as a calculated table, or wrap with CONCATENATEX to show as a comma list.

D) % of Selected Table vs All

Selected Rows (table) =
CALCULATETABLE('Superstore')  -- current context table

All Rows (table) =
CALCULATETABLE('Superstore', REMOVEFILTERS('Superstore'))

% Selected vs All =
DIVIDE(
  SUMX(Selected Rows (table), 'Superstore'[Sales]),
  SUMX(All Rows (table), 'Superstore'[Sales]),
  0
)

Great for % of total that **respects** current slicers (top) vs **ignores** (bottom).

Common Pitfalls & Tips

  • Row vs Filter context: CALCULATE transitions row → filter context; CALCULATETABLE returns a table that you must iterate.
  • Performance: Avoid huge virtual tables; summarize first (see SUMMARIZE).
  • Clarity: If you need a number → start with CALCULATE. If you need a set of rows → use CALCULATETABLE.

Power BI DAX — Interactive Quiz

Covers: CALCULATE, CALCULATE vs CALCULATETABLE, SUMMARIZE, DISTINCT vs VALUES, KEEPFILTERS, REMOVEFILTERS, Time Intelligence, RELATED/LOOKUPVALUE, and set operations.

Question 1 of 18
Loading…

Power BI DAX — Frequently Asked Questions

Quick answers with deep dives linked to relevant sections of this guide.

What is DAX in Power BI and why should beginners learn it?
DAX (Data Analysis Expressions) powers measures, calculated columns, and tables for analytics. Start here: Power BI DAX Tutorial for Beginners.
When should I use a Measure vs a Calculated Column?
Measures recalc with filters (for visuals). Columns compute once per row at refresh. See the quick rule in Section 1.
CALCULATE vs CALCULATETABLE — what’s the practical difference?
CALCULATE returns a number; CALCULATETABLE returns a table to iterate with SUMX/COUNTROWS. Examples: Mastering DAX: CALCULATE vs CALCULATETABLE.
How do I compute % of Grand Total safely?
Use REMOVEFILTERS to clear context for the denominator:
Grand Total = CALCULATE([Total Sales], REMOVEFILTERS('Superstore'))% of GT = DIVIDE([Total Sales], [Grand Total]). Learn more: REMOVEFILTERS.
KEEPFILTERS vs REMOVEFILTERS — which one should I use?
KEEPFILTERS = intersect with existing slicers; REMOVEFILTERS = clear filters first. Compare patterns: KEEPFILTERS tutorial and REMOVEFILTERS tutorial.
DISTINCT vs VALUES — what’s the key difference?
DISTINCT returns unique values (ignores BLANK). VALUES respects current filter context and may include BLANK. See examples: Using the DISTINCT Function.
How do I build grouped tables for Top-N or rankings?
Use SUMMARIZE/SUMMARIZECOLUMNS to create virtual groups, then TOPN or RANKX. Step-by-step: SUMMARIZE tutorial.
Do I need a Date table for Time Intelligence (YTD/MTD/QTD)?
Yes—mark a proper Date table and relate it to your fact. Learn YTD/MTD/LY patterns in Time Intelligence.
When should I use RELATED vs LOOKUPVALUE?
RELATED (faster) requires a relationship; LOOKUPVALUE works without one (handy for disconnected mappings). See: RELATED and LOOKUPVALUE.
How do set operations (UNION, INTERSECT, EXCEPT) help analysis?
They compare lists—e.g., “regions with orders vs customers.” See the diagram + code in One-File Demo (Set Ops).
What’s the safest way to divide or create KPIs?
Use DIVIDE(numerator, denominator, 0) to avoid divide-by-zero. Try it in the Quick Start.
Where can I test my knowledge with an interactive DAX quiz?
Right here: Interactive Power BI DAX Quiz (progress bar, review, retake).

Further Reading & Tools

Keep exploring Power BI and DAX with these hand-picked guides from Vista Academy.

Build job-ready skills: Enroll in our industry-aligned programs (live classes + projects + mentoring).

Best Data Analytics Course — Dehradun, Uttarakhand

Excel → SQL → Power BI → Python. Portfolio projects and placement support.

Best Data Science Course — Dehradun

Statistics, Python, ML, model deployment. Learn by building real projects.

Business Analytics Course — Dehradun

Solve business problems with BI dashboards, data storytelling, and KPIs.

3-Month Machine Learning Course — Dehradun

Hands-on ML bootcamp: supervised/unsupervised models, evaluation, deployment.

Vista Academy – 316/336, Park Rd, Laxman Chowk, Dehradun – 248001
📞 +91 94117 78145 | 📧 thevistaacademy@gmail.com | 💬 WhatsApp
💬 Chat on WhatsApp: Ask About Our Courses