Microsoft Power BI • DAX and Measures

Conditional Logic in DAX — Use IF, SWITCH, and basic boolean logic in measures

Master branching expressions inside calculated measures to build intelligent, context-aware Power BI reports.

Microsoft Power BI emblem with a dashboard, stacked chart, and database.
Inside this lesson 10 sections 5 questions 9 figures

SECTION 1

Historical Context & Motivation

Business intelligence tools have always needed a way to express conditional logic—deciding which value to return based on the current state of the data. In the spreadsheet era, Excel's IF function was the workhorse for branching calculations. When Microsoft introduced the tabular data model in SQL Server Analysis Services (SSAS) Tabular around 2012, the team needed an expression language that felt familiar to Excel power users yet could operate over entire tables with filter context. That language became DAX (Data Analysis Expressions), and it carried forward conditional functions like IF and SWITCH while adding evaluation semantics unique to columnar in-memory engines.

2009 • PowerPivot Add-in for Excel

Microsoft ships PowerPivot as a free Excel add-in, introducing DAX as the formula language for in-memory tabular models. IF and basic boolean operators are available from day one.

2012 • SSAS Tabular & SWITCH

SQL Server Analysis Services 2012 adds a full Tabular model. The SWITCH function appears, giving analysts a cleaner multi-branch alternative to deeply nested IF statements.

2015 • Power BI Desktop Released

Power BI Desktop brings DAX to a modern self-service BI platform with monthly updates, making conditional measures accessible to a much wider audience.

2018–Present • Performance Optimizations & Best Practices

The community standardizes on SWITCH(TRUE(), …) as the idiomatic DAX pattern for multi-condition branching. Engine improvements allow short-circuit evaluation, making conditional measures faster in large models.

The fundamental question DAX conditional logic answers is this: how do you write a single measure that adapts its calculation based on the filter context or data characteristics at evaluation time? Unlike a stored column, a measure is evaluated on the fly every time a visual queries the model, so conditional branching inside measures enables dynamic KPIs, tiered classifications, and context-sensitive aggregations—all without duplicating data.

SECTION 2

Core Principles & Definitions

Before diving into syntax, it is essential to understand the foundational ideas that govern conditional logic in DAX. Unlike imperative languages such as Python or Java, DAX is a functional, declarative language—there are no loops, no mutable variables, and no procedural control flow. Branching is therefore expressed entirely through function calls that return scalar values. Every conditional expression must ultimately collapse to a single value because a measure cell in a Power BI visual is always a scalar.

1

Boolean Expressions as First-Class Values

In DAX, TRUE() and FALSE() are functions returning boolean scalars. Comparison operators (=, <>, <, >, <=, >=) and logical functions (AND, OR, NOT) compose into boolean expressions that serve as predicates for IF and SWITCH.
2

IF — Binary Branch

IF(<condition>, <value_if_true>, <value_if_false>) evaluates a single boolean predicate and returns one of two results. The else-branch is optional; when omitted, DAX returns BLANK().
3

SWITCH — Multi-Branch Dispatch

SWITCH(<expression>, <value1>, <result1>, …, [<else_result>]) matches an expression against multiple literal values. The SWITCH(TRUE(), …) idiom generalizes this to arbitrary boolean conditions.
4

Short-Circuit Evaluation

DAX evaluates IF and SWITCH lazily: once the engine identifies the matching branch, the remaining branches are not evaluated, reducing unnecessary computation in expensive measures.
5

Row Context vs. Filter Context

Boolean predicates inside a measure operate under filter context by default. Inside iterator functions like SUMX, conditions also have access to row context, enabling row-level branching within an aggregation.
✦

KEY TAKEAWAY

Think of a DAX measure with conditional logic as a pure function in the functional programming sense: it takes the current filter context as its implicit argument, evaluates a predicate, and deterministically returns a scalar. Just as a pattern-matching expression in Haskell or a ternary operator in C selects between alternatives without side effects, IF and SWITCH in DAX are side-effect-free selectors that pick among pre-declared result expressions.

SECTION 3

Visual Explanation — Evaluation Flow

The diagram below illustrates how the DAX engine evaluates a conditional measure. When a visual cell queries the model, the engine first resolves the filter context, then evaluates the boolean predicate inside the IF or SWITCH function. Depending on the result, exactly one branch is selected, and only that branch's expression is fully computed—the other branches are skipped.

IF / SWITCH Evaluation Flow Inside a MeasureVisual Cell Queries ModelResolve Filter ContextEvaluatePredicateTRUEFALSEEvaluate TRUE Branch(value_if_true)Evaluate FALSE Branch(value_if_false / else)Scalar Result AScalar Result BReturn to Visual Cell
The diamond node represents predicate evaluation. Only the matching branch (green for TRUE, red for FALSE) is computed; the other is short-circuited. The final scalar result flows back to the visual cell.

Notice that the diamond decision node mirrors the classic flowchart idiom from introductory programming courses; however, in DAX there is no sequential execution—the entire expression tree is declared and the engine's query optimizer decides the most efficient physical plan. The key takeaway from this diagram is that conditional measures are expressions, not statements, and they always resolve to a single scalar per filter-context cell.

SECTION 4

Function Signatures & Boolean Algebra in DAX

IF Function Signature

IF SYNTAX

IF(<logicaltest>,<valueiftrue>[,<valueiffalse>])IF( <logical_test>, <value_if_true> [, <value_if_false>] )

logical_test — any expression that returns TRUE or FALSE. value_if_true — returned when predicate holds. value_if_false — optional; defaults to BLANK() when omitted.

SWITCH Function Signature

SWITCH SYNTAX

SWITCH(<expression>,<value1>,<result1>,…,[<elseresult>])SWITCH( <expression>, <value1>, <result1>, … , [<else_result>] )

expression — evaluated once and compared to each value in order. value_n — literal to compare against. result_n — returned on match. else_result — optional default.

SWITCH(TRUE(), …) Pattern

SWITCH TRUE IDIOM

SWITCH(TRUE(),<cond1>,<res1>,<cond2>,<res2>,…,[<else>])SWITCH( TRUE(), <cond1>, <res1>, <cond2>, <res2>, … , [<else>] )

By passing TRUE() as the expression, each cond_n becomes a boolean test. The first condition that evaluates to TRUE wins. This replaces nested IF chains.

Boolean Operators in DAX

DAX provides three logical operators that combine boolean sub-expressions. The && operator (or the AND function) returns TRUE only when both operands are TRUE, analogous to the logical conjunction ∧. The || operator (or the OR function) returns TRUE when at least one operand is TRUE (logical disjunction ∨). The NOT function negates a boolean value (logical complement ¬). These compose freely inside IF and SWITCH predicates, so complex business rules can be expressed as single-line boolean formulas.

BOOLEAN COMPOSITION

IF( [Revenue] > 100000 && NOT( [IsReturned] ), "High Value", "Standard" )

&& — logical AND. NOT() — logical negation. The predicate is TRUE only for high-revenue, non-returned transactions.

SECTION 5

Common Conditional Patterns & Classification

In practice, conditional logic in DAX appears in a small number of recurring patterns. Recognizing these patterns accelerates development and avoids common pitfalls such as deeply nested IF trees that become difficult to read and maintain. The following diagram categorizes the most important patterns and shows when to use each one.

DAX Conditional Pattern Decision TreeHow many branches?2 branches3+ branchesUse IF()Matching on equality?YesNo (ranges)Use SWITCH(expr, …)Use SWITCH(TRUE(), …)Pattern A — Simple IFIF([Sales] > 1000,"Above Target","Below Target")Pattern B — SWITCHSWITCH([Region],"US", 0.08,"EU", 0.20,0)Pattern C — SWITCH TRUESWITCH(TRUE(),[Score]>=90, "A",[Score]>=80, "B",[Score]>=70, "C","F")
Decision tree for selecting the right conditional pattern: two branches → IF; multiple equality matches → SWITCH; multiple range/inequality checks → SWITCH(TRUE(), …). Code snippets at the bottom illustrate each pattern.
PatternWhen to UseExample Scenario
IF()Exactly two outcomes from a single boolean testFlag orders as "On Time" or "Late"
Nested IF()2–3 levels only; beyond that, readability degradesTraffic light KPI: Green / Yellow / Red
SWITCH(expr, …)Matching a column or variable against discrete literal valuesMap month number to month name
SWITCH(TRUE(), …)Multiple range tests, inequality predicates, or complex boolean conditionsAssign letter grades based on score ranges
Boolean arithmeticCounting rows that satisfy a condition (TRUE = 1, FALSE = 0)Count overdue invoices without CALCULATE

Common conditional patterns in DAX measures

SECTION 6

Worked Example — Dynamic Profit-Tier Measure

Suppose you have a sales table with columns Sales[Revenue] and Sales[Cost]. The business wants a measure that computes total profit and labels it into one of four tiers: "Loss", "Low", "Medium", or "High". We will build this step by step.

Profit Tier Measure

  1. 1

    Step 1 — Define Base Measures

    First, create the building-block measures. Total Revenue = SUM(Sales[Revenue]) and Total Cost = SUM(Sales[Cost]). These are simple aggregation measures that will supply inputs to the conditional logic.
    Total Profit = [Total Revenue] − [Total Cost]
  2. 2

    Step 2 — Store Intermediate Value with VAR

    To avoid recalculating profit inside every branch, use a VAR to capture the profit once. VAR declarations in DAX are immutable and evaluated exactly once, similar to a let-binding in functional languages.
    VAR _profit = [Total Revenue] − [Total Cost]
  3. 3

    Step 3 — Apply SWITCH(TRUE(), …) for Range Classification

    We have four tiers defined by ranges, so SWITCH(TRUE(), …) is the appropriate pattern. The conditions are ordered from highest to lowest, so the first match returns immediately. Notice that the order matters: if we put _profit >= 0 first, it would match for all non-negative profits and we would never reach the "Medium" or "High" branches.
    RETURN SWITCH(TRUE(), _profit >= 100000, "High", _profit >= 50000, "Medium", _profit >= 0, "Low", "Loss")
  4. 4

    Step 4 — Complete Measure Definition

    Combining all steps into a single measure definition that can be added to the model via the DAX editor in Power BI Desktop:
    Profit Tier = VAR _profit = [Total Revenue] − [Total Cost] RETURN SWITCH(TRUE(), _profit >= 100000, "High", _profit >= 50000, "Medium", _profit >= 0, "Low", "Loss")
  5. 5

    Step 5 — Validate in a Matrix Visual

    Place [Profit Tier] in a matrix visual alongside [Total Profit]. Each row inherits a different filter context (e.g., by region or product category), so the tier label adapts per row. For a region with profit of 72 000, the measure returns "Medium"; for a region at −5 000, it returns "Loss".
    Region A → 72 000 → "Medium" | Region B → −5 000 → "Loss" | Region C → 130 000 → "High"
💡

Why VAR Matters

Without the VAR, the expression [Total Revenue] − [Total Cost] would be evaluated separately for each branch the engine inspects. While short-circuit evaluation mitigates this somewhat, using VAR guarantees a single evaluation, improves readability, and follows the DAX community best practice endorsed by SQLBI and Microsoft documentation.

SECTION 7

IF vs. SWITCH — Strengths & Limitations

DimensionIF()SWITCH()
ReadabilityClear for 1–2 levels; degrades rapidly with nesting beyond 3 levelsFlat structure even with 10+ branches; easy to scan and modify
PerformanceBoth short-circuit. Deeply nested IF may produce larger query plansEquivalent or slightly better for many branches due to simpler plan
FlexibilitySupports any boolean expression nativelyNative form requires equality; SWITCH(TRUE(), …) needed for ranges
Default BehaviorReturns BLANK() when else-branch is omittedReturns BLANK() when else-result is omitted
Type SafetyAll branches should return the same data type; DAX coerces silentlySame rule applies; mixing types can cause unexpected coercion
Best Use CaseBinary flags, simple thresholds, inline ternary-style checksMapping codes to labels, grading scales, multi-bucket KPIs

Head-to-head comparison of IF and SWITCH in DAX

✦

KEY TAKEAWAY

In software engineering terms, choosing between IF and SWITCH is analogous to choosing between an if-else ladder and a switch/match expression in languages like Rust or Kotlin. The semantic difference is minimal, but the syntactic clarity matters enormously in production DAX models where dozens of measures may reference each other. Prefer SWITCH(TRUE(), …) whenever you have three or more conditions—your future self (and your teammates) will thank you during code review.

SECTION 8

Connection to Advanced DAX Patterns

Conditional logic in basic measures is the gateway to several advanced DAX techniques. Once you are comfortable with IF and SWITCH, the natural next steps involve combining them with CALCULATE to alter filter context dynamically, using iterator functions like SUMX and FILTER to apply row-level conditional logic across tables, and leveraging calculation groups (introduced in 2019) to parameterize measure behavior without duplicating conditional measures.

This LessonAdvanced Extension
IF([Sales] > 1000, …)CALCULATE + FILTER — apply the condition as a filter rather than a branch, enabling set-based operations
SWITCH(TRUE(), …) in a measureCalculation Groups — centralize branch logic across many measures via a single SELECTEDMEASURE() call
Boolean predicates with && and ||Row-level security (RLS) — boolean DAX expressions gate access to rows at the model level
VAR for intermediate resultsMulti-step VAR chains that compose conditional branches with time-intelligence functions like SAMEPERIODLASTYEAR

From basic conditional measures to advanced DAX

A particularly powerful pattern is combining SWITCH with disconnected tables (also known as parameter tables). You create a small table with labels like {"Revenue", "Profit", "Margin"}, expose it as a slicer, and use SWITCH(SELECTEDVALUE(Metric[Name]), "Revenue", [Total Revenue], "Profit", [Total Profit], "Margin", [Profit Margin]) to let end users toggle which measure a chart displays. This is a standard enterprise BI technique that relies entirely on the conditional logic principles covered in this lesson.

SECTION 9

Practice Problems

Question 1: CONCEPTUAL

Explain why the order of conditions matters in a SWITCH(TRUE(), …) expression. What happens if the broadest condition is listed first?
Show answer
SWITCH(TRUE(), …) evaluates conditions sequentially and returns the result for the first condition that evaluates to TRUE. If the broadest condition (e.g., _score >= 0) is placed first, it will match virtually every row, and the more specific conditions below it will never be reached. This is analogous to putting the base case before the recursive case in a pattern match—the function short-circuits on the first match. Always order conditions from most restrictive to least restrictive to ensure correct classification.

Question 2: BASIC CALCULATION

Write a DAX measure called Order Status that returns "Shipped" if [Ship Date] is not blank, and "Pending" otherwise. Use the IF function.
Show answer
The measure uses IF combined with NOT and ISBLANK: Order Status = IF( NOT(ISBLANK([Ship Date])), "Shipped", "Pending" ). ISBLANK returns TRUE when the value is BLANK (DAX's equivalent of NULL). The NOT function negates it, so the predicate reads as "if Ship Date is present." In a card or table visual, this measure will dynamically reflect the current filter context—if a slicer filters to shipped orders only, the measure returns "Shipped" for every visible row.

Question 3: INTERMEDIATE

You have a measure [Avg Response Time] in hours. Write a measure SLA Status that returns "Excellent" if the average is under 1 hour, "Acceptable" if under 4 hours, "Warning" if under 8 hours, and "Breach" otherwise. Use SWITCH(TRUE(), …) with a VAR.
Show answer
The measure is: SLA Status = VAR _avg = [Avg Response Time] RETURN SWITCH(TRUE(), _avg < 1, "Excellent", _avg < 4, "Acceptable", _avg < 8, "Warning", "Breach"). The VAR captures the intermediate result to avoid recalculation. The conditions are ordered from most restrictive to least restrictive. For an average of 3.5 hours, the first condition (_avg < 1) is FALSE, the second (_avg < 4) is TRUE, so "Acceptable" is returned. The remaining conditions are not evaluated due to short-circuit behavior.

Question 4: APPLIED

A retail company wants a single measure that switches the displayed metric based on a slicer backed by a disconnected table called MetricSelector with a column [MetricName] containing values "Revenue", "Units", and "Avg Price". Write the measure Dynamic KPI assuming base measures [Total Revenue], [Total Units], and [Avg Price] already exist.
Show answer
The measure leverages SELECTEDVALUE to read the slicer's selection and SWITCH to dispatch: Dynamic KPI = SWITCH( SELECTEDVALUE(MetricSelector[MetricName]), "Revenue", [Total Revenue], "Units", [Total Units], "Avg Price", [Avg Price], BLANK() ). SELECTEDVALUE returns the single value in the filter context or BLANK() if multiple values are selected. The SWITCH maps each string to the corresponding base measure. The trailing BLANK() is the else-result, ensuring the visual shows nothing when no metric is selected. This pattern is standard in enterprise dashboards where visual real estate is limited and users need to toggle between KPIs.

Question 5: CRITICAL THINKING

Consider a measure that uses nested IF statements five levels deep to categorize products. Refactor it into a SWITCH(TRUE(), …) version and discuss: (a) under what circumstances the two forms would produce different results, and (b) how the DAX engine's query plan might differ between the nested IF version and the SWITCH version. Reference short-circuit evaluation in your analysis.
Show answer
From a semantic perspective, a correctly ordered SWITCH(TRUE(), …) produces identical results to the equivalent nested IF chain, because both evaluate conditions top-to-bottom and return on the first match. However, differences can arise if the nested IF version has inconsistent nesting—e.g., placing a condition in the else-branch of the wrong level, which is a common bug in deep nesting. The flat SWITCH structure eliminates this class of error. Regarding query plans, the DAX engine's formula engine translates both forms into an internal decision tree. Deeply nested IFs can produce a wider tree with more intermediate nodes, increasing the formula engine's workload. SWITCH tends to generate a flatter plan that the engine optimizes into a hash-lookup-style dispatch for equality matches, or a sequential scan for SWITCH(TRUE()). Both forms support short-circuit evaluation: once a branch matches, remaining branches are pruned. In practice, the performance difference is negligible for fewer than ten branches, but SWITCH's readability advantage compounds as model complexity grows, reducing maintenance cost—a concern that mirrors software engineering principles of preferring flat, declarative structures over deeply nested imperative logic.

SUMMARY

Lesson Summary

Summary

Conditional logic in DAX revolves around three tools: the IF function for binary branching, the SWITCH function for multi-branch dispatch (especially the SWITCH(TRUE(), …) idiom for range-based conditions), and boolean operators (&&, ||, NOT) for composing predicates. These are expression-level constructs—not procedural statements—and they always resolve to a single scalar value per filter-context cell.

Best practices include using VAR to capture intermediate computations, ordering SWITCH conditions from most restrictive to least restrictive, avoiding nesting IF beyond two or three levels, and leveraging disconnected tables with SWITCH to build dynamic, user-driven visuals. Mastering these patterns lays the groundwork for advanced DAX involving CALCULATE, iterators, and calculation groups.

Varsity Tutors • Microsoft Power BI • Conditional Logic in DAX — Use IF, SWITCH, and basic boolean logic in measures