Wicked Smart Data
LearnArticlesAbout
Sign InSign Up
LearnArticlesAboutContact
Sign InSign Up
Wicked Smart Data

The go-to platform for professionals who want to master data, automation, and AI — from Excel fundamentals to cutting-edge machine learning.

Platform

  • Learning Paths
  • Articles
  • About
  • Contact

Connect

  • Contact Us
  • RSS Feed

© 2026 Wicked Smart Data. All rights reserved.

Privacy PolicyTerms of Service
All Articles
DAX Aggregation Functions Demystified: SUM, SUMX, COUNT, COUNTX, and When to Use Each

DAX Aggregation Functions Demystified: SUM, SUMX, COUNT, COUNTX, and When to Use Each

Power BI🌱 Foundation15 min readJul 15, 2026Updated Jul 15, 2026
Table of Contents
  • Introduction
  • Prerequisites
  • What Is an Aggregation Function, Really?
  • SUM: The Simple Column Aggregator
  • Syntax
  • A Real Example
  • What SUM Can and Cannot Do
  • COUNT and COUNTA: Counting What's There
  • Syntax
  • A Real Example
  • SUMX: The Iterator That Calculates Before It Sums
  • Syntax
  • The Classic Example: Revenue from Quantity × Price
  • Going Further: Conditional Logic Inside SUMX

DAX Aggregation Functions Demystified: SUM, SUMX, COUNT, COUNTX, and When to Use Each

Introduction

Imagine you've just loaded a sales dataset into Power BI. Your manager wants three things on the dashboard by end of day: total revenue, number of completed orders, and average revenue per transaction. You open the data model, stare at the fields panel, and think — "I'll just drag Sales Amount onto the canvas and it'll figure it out." And honestly? Sometimes it does. But the moment your manager adds a fourth request — "Can you also show me revenue only for orders where the margin was above 15%?" — the drag-and-drop approach hits a wall. That's the moment you need to understand DAX aggregation functions properly, not just use them by accident.

DAX (Data Analysis Expressions) is the formula language built into Power BI, Excel Power Pivot, and Analysis Services. At its core, DAX is designed to aggregate, filter, and calculate across tables of data. The aggregation functions are the workhorses of DAX — they're what turn a column of a million numbers into a single meaningful figure. But DAX gives you two distinct families of these functions: the simple aggregators like SUM and COUNT, and the iterator functions like SUMX and COUNTX. Understanding the difference between them is one of the most important conceptual leaps you'll make in your DAX journey.

By the end of this lesson, you'll know exactly which function to reach for in any aggregation scenario, why iterators exist, and how to avoid the most common traps that trip up beginners.

What you'll learn:

  • What SUM and COUNT do and when they're the right tool
  • What SUMX and COUNTX do differently — and why that matters
  • How iterator functions evaluate row-by-row expressions
  • How to choose between simple and iterator aggregators for real business calculations
  • How filter context affects all four functions

Prerequisites

  • You have Power BI Desktop installed (free download from microsoft.com/power-bi)
  • You're comfortable with the concept of tables and columns in a data model
  • You've created at least one measure or calculated column before — even a simple one like Total Sales = SUM(Sales[Amount])
  • You don't need to know advanced DAX — this lesson starts from the ground up

What Is an Aggregation Function, Really?

Before we get into the specific functions, let's make sure the concept is rock solid.

A column in a data table stores one value per row. Your Sales table might have 50,000 rows, each representing one transaction, with a SalesAmount column storing the dollar value of that transaction. An aggregation function takes all those individual values and produces a single summary number — a total, a count, an average, a maximum.

In DAX, you write aggregation functions inside measures. A measure is a named calculation that lives in your data model and gets re-evaluated every time the visual it's in changes context — for example, when a user clicks a filter or selects a different time period. This is different from a calculated column, which is computed once when the data loads and stored row-by-row.

For now, all the examples in this lesson will be measures. We'll write them using the DAX formula bar in Power BI, which you access by selecting the table you want the measure to live in, then clicking "New Measure" in the Home ribbon.


SUM: The Simple Column Aggregator

SUM is the most fundamental aggregation in DAX. It takes a single column reference and adds up all the values in that column, subject to whatever filter context is active.

Syntax

SUM(<column>)

A Real Example

Say your Sales table has a column called LineTotal that stores the dollar amount for each sale. You want a measure that shows total revenue:

Total Revenue = SUM(Sales[LineTotal])

That's it. Drop this measure into a card visual and you'll see total revenue. Drop it into a bar chart with Category on the axis and Power BI will automatically filter the SUM to each category's rows. That automatic filtering behavior is called filter context, and it's what makes SUM so powerful with so little code.

What SUM Can and Cannot Do

SUM is limited in one important way: it can only reference a single existing column. It cannot perform a calculation row-by-row before summing. That sounds abstract, so let's make it concrete.

Suppose your Sales table stores Quantity and UnitPrice separately, but not a pre-calculated LineTotal. If you want total revenue, you might instinctively write:

-- This will NOT work
Total Revenue = SUM(Sales[Quantity] * Sales[UnitPrice])

DAX will throw an error. SUM expects a column reference, not an expression. You can't multiply two columns inside a SUM. This is exactly the gap that SUMX fills.

Tip: If your data already has the final value you need in a single column, use SUM. It's faster and simpler. Only reach for SUMX when you need to calculate something row-by-row before aggregating.


COUNT and COUNTA: Counting What's There

COUNT is DAX's basic row-counting function for numeric columns. It counts the number of rows that contain a numeric value in the specified column, ignoring blanks.

Syntax

COUNT(<column>)

A Real Example

Imagine you want to know how many sales transactions occurred:

Number of Transactions = COUNT(Sales[OrderID])

Wait — OrderID is probably a text or whole number identifier. Here's something beginners often get caught out by: COUNT only counts numeric values. If OrderID is stored as text (which is common for IDs that might contain letters or leading zeros), COUNT will return zero or cause an error.

For counting rows regardless of data type, use COUNTA:

Number of Transactions = COUNTA(Sales[OrderID])

COUNTA counts any non-blank value, whether it's a number, text, date, or boolean. In practice, when you want to count rows in a transaction table, COUNTA on any reliable non-blank column is your friend.

There's also COUNTROWS, which directly counts the number of rows in a table:

Number of Transactions = COUNTROWS(Sales)

COUNTROWS is often the cleanest option when you want to count transactions, because it makes your intent explicit — you're counting rows, not values in a specific column.

When to use which:

  • COUNT — counting rows where a specific numeric column is populated
  • COUNTA — counting rows where any column is populated (works on text, dates, etc.)
  • COUNTROWS — counting all rows in a table, often the most direct and readable choice

SUMX: The Iterator That Calculates Before It Sums

Now we get to the really interesting part. SUMX is an iterator function — a category of DAX functions that loop through a table row by row, evaluate an expression for each row, and then aggregate the results.

Syntax

SUMX(<table>, <expression>)

There are two arguments: the table to iterate over, and the expression to evaluate for each row of that table. The expression can reference any column in the table, perform calculations, or even call other functions.

The Classic Example: Revenue from Quantity × Price

Going back to our earlier problem — Quantity and UnitPrice are stored separately, and we need total revenue:

Total Revenue = SUMX(Sales, Sales[Quantity] * Sales[UnitPrice])

Here's what DAX does when this measure is evaluated:

  1. It visits row 1 of the Sales table, multiplies Quantity by UnitPrice for that row, and holds onto the result.
  2. It visits row 2, does the same calculation, holds onto that result.
  3. It continues through every row in the table.
  4. At the end, it sums all those row-level results together.

This is the iterator pattern: evaluate an expression for each row, then aggregate. The result is exactly what you'd expect — total revenue calculated from the correct per-row multiplication.

Going Further: Conditional Logic Inside SUMX

Because the second argument of SUMX is an expression, you can put any valid DAX expression there — including IF statements. This is where iterators really start to flex.

Say your manager wants to see total revenue only for high-margin products, where margin is calculated as (UnitPrice - UnitCost) / UnitPrice. You want to sum revenue for rows where margin exceeds 15%.

High Margin Revenue = 
SUMX(
    Sales,
    IF(
        (Sales[UnitPrice] - Sales[UnitCost]) / Sales[UnitPrice] > 0.15,
        Sales[Quantity] * Sales[UnitPrice],
        0
    )
)

For each row, DAX checks whether the margin exceeds 15%. If it does, it includes that row's revenue in the sum. If not, it contributes zero. The final sum contains only high-margin revenue.

Warning: SUMX iterates over every row in the table, which means it can be slow on very large tables if the expression is complex. For simple cases where the column already exists, always prefer SUM. Reserve SUMX for cases where you genuinely need row-level calculation.


COUNTX: Counting Rows That Meet an Expression

COUNTX follows the same iterator pattern as SUMX, but instead of summing a row-level expression, it counts the number of rows for which the expression returns a non-blank value.

Syntax

COUNTX(<table>, <expression>)

A Real Example

Suppose you want to count how many transactions had a calculated margin above 15%:

High Margin Transaction Count = 
COUNTX(
    Sales,
    IF(
        (Sales[UnitPrice] - Sales[UnitCost]) / Sales[UnitPrice] > 0.15,
        1,
        BLANK()
    )
)

For each row, the IF expression returns either 1 (a non-blank value) or BLANK(). COUNTX counts the rows where the result is non-blank — effectively counting only the high-margin transactions.

That said, in practice, COUNTX is often replaceable with COUNTROWS combined with FILTER, which can be more readable:

High Margin Transaction Count = 
COUNTROWS(
    FILTER(
        Sales,
        (Sales[UnitPrice] - Sales[UnitCost]) / Sales[UnitPrice] > 0.15
    )
)

Both approaches work. The FILTER + COUNTROWS pattern is often preferred for readability — it clearly says "count the rows in this filtered subset." COUNTX shines more when your expression is more complex or when you want to count distinct calculated values.


Understanding the Iterator Mental Model

The concept of row-by-row iteration is so important in DAX that it's worth pausing to build a clear mental model.

Think of it like a spreadsheet formula that you've typed in one cell, then dragged down the entire column. In Excel, if you put =B2*C2 in cell D2 and drag it down, each row gets its own calculation. SUMX is DAX's way of saying: "Do that dragging-down thing for every row, and then give me the sum of that whole column."

The two-argument structure reinforces this:

  • First argument (table): "How many rows are you dragging down?" — define the table to iterate over
  • Second argument (expression): "What formula goes in each cell?" — the per-row calculation

You can even iterate over a filtered table by wrapping the first argument in a FILTER call:

Online Revenue = 
SUMX(
    FILTER(Sales, Sales[Channel] = "Online"),
    Sales[Quantity] * Sales[UnitPrice]
)

This limits the iteration to only Online channel rows before doing the multiplication and sum.


Choosing Between SUM/COUNT and SUMX/COUNTX

Here's a practical decision framework:

Use SUM when:

  • The value you need to aggregate already exists in a single column
  • You don't need to calculate anything row by row
  • Example: Total Revenue = SUM(Sales[LineTotal]) — LineTotal is pre-calculated

Use SUMX when:

  • You need to multiply, divide, or combine two columns before summing
  • You want to apply conditional logic at the row level before aggregating
  • You're summing a value that doesn't exist as a column yet
  • Example: Revenue from Quantity × UnitPrice

Use COUNT / COUNTA / COUNTROWS when:

  • You want a simple count of rows or populated values
  • No per-row expression is needed
  • Example: Total number of orders

Use COUNTX when:

  • You need to count rows based on a calculated condition that isn't a simple column value
  • Your counting logic requires per-row expressions
  • Example: Count of transactions where a calculated margin exceeds a threshold

The Golden Rule: If you can write it with a simple aggregator, do so. Iterators are more powerful, but simple aggregators are faster to write, easier to read, and often more performant on large datasets.


Hands-On Exercise

Let's build five measures using a realistic scenario. Imagine you have a Sales table with these columns:

  • OrderID (text)
  • ProductName (text)
  • Quantity (whole number)
  • UnitPrice (decimal)
  • UnitCost (decimal)
  • Channel (text: "Online" or "In-Store")

Create a new Power BI Desktop file, create a blank table with these columns (you can use Enter Data in the Home ribbon to type in a small dataset — use 10–15 rows of made-up but realistic sales data), then create each of the following measures by clicking on your table in the Fields pane, selecting "New Measure" from the ribbon, and typing the formula:

Measure 1 — Total Revenue (using SUMX, since LineTotal doesn't exist):

Total Revenue = SUMX(Sales, Sales[Quantity] * Sales[UnitPrice])

Measure 2 — Total Cost:

Total Cost = SUMX(Sales, Sales[Quantity] * Sales[UnitCost])

Measure 3 — Total Profit (using SUM of derived measures):

Total Profit = [Total Revenue] - [Total Cost]

Measure 4 — Number of Orders:

Number of Orders = COUNTROWS(Sales)

Measure 5 — Number of Profitable Orders (where UnitPrice > UnitCost):

Profitable Orders = 
COUNTX(
    Sales,
    IF(Sales[UnitPrice] > Sales[UnitCost], 1, BLANK())
)

After creating these measures, build a table visual on the canvas and add all five measures as columns. Then add a slicer for Channel and observe how all five measures update automatically when you filter by channel. This is filter context in action — every measure responds to the slicer without you writing any filtering logic in the measures themselves.


Common Mistakes and Troubleshooting

Mistake 1: Trying to Put an Expression Inside SUM

-- Wrong
Total Revenue = SUM(Sales[Quantity] * Sales[UnitPrice])

-- Right
Total Revenue = SUMX(Sales, Sales[Quantity] * Sales[UnitPrice])

SUM expects a column name, not a formula. If you need to compute something before summing, use SUMX.

Mistake 2: Using COUNT on a Text Column

-- Returns 0 or an error if OrderID is text
Number of Orders = COUNT(Sales[OrderID])

-- Works regardless of data type
Number of Orders = COUNTA(Sales[OrderID])
-- Or even better
Number of Orders = COUNTROWS(Sales)

Mistake 3: Forgetting That SUMX Iterates the Entire Table by Default

If you write SUMX(Sales, ...) inside a measure that's already being filtered by a visual, SUMX will iterate only the filtered rows — that's usually what you want. But if you explicitly pass an unfiltered table using ALL(Sales), you'll get the grand total regardless of filters. Be intentional about your table argument.

Mistake 4: Nesting SUMX Inside SUMX Unnecessarily

Beginners sometimes write deeply nested iterators when a simpler approach would work. If you find yourself writing SUMX inside SUMX, pause and ask whether you can restructure the calculation using intermediate measures. Breaking complex calculations into smaller named measures makes your model far more maintainable.

Mistake 5: Confusing Measures with Calculated Columns

Aggregation functions like SUM and SUMX are designed for measures — they aggregate across multiple rows in a filter context. If you try to use SUM in a calculated column, DAX will sum the entire column and return the same grand total on every row, which is almost never what you want. In a calculated column, you reference individual row values directly: Sales[Quantity] * Sales[UnitPrice] — no aggregation function needed.


Summary and Next Steps

You now have a solid foundation in four of DAX's most essential functions. Here's the core of what you've learned:

  • SUM aggregates an existing column of numbers — fast, simple, use it when the value already exists in your data.
  • COUNT / COUNTA / COUNTROWS count populated values or rows — choose based on your column's data type and what you're counting.
  • SUMX iterates row-by-row, evaluates an expression for each row, then sums the results — essential when you need per-row calculations before aggregating.
  • COUNTX does the same but counts non-blank expression results — useful for conditional counting scenarios.

The conceptual leap from simple aggregators to iterators is one of the most important milestones in learning DAX. Once you understand that SUMX is just "calculate something for every row, then add it all up," a huge range of business calculations become approachable.

Where to go from here:

  • AVERAGEX — the averaging iterator, follows the same pattern as SUMX
  • CALCULATE — the most important function in DAX, used to modify filter context around any aggregation
  • FILTER — used as a table argument inside iterators to pre-filter which rows get iterated
  • RELATED — used inside iterators to pull values from related tables, enabling cross-table row-level calculations

Mastering aggregation functions is your foundation. Every advanced DAX calculation you'll ever write builds on these patterns. The more comfortable you become with the iterator model, the faster complex measures will click into place.

Learning Path: DAX Mastery

Previous

Mastering DAX Window Functions: RANK, ROWNUMBER, and OFFSET for Advanced Comparative Analysis

Related Articles

Power BI🌱 Foundation

Understanding the Power BI Ecosystem: Desktop, Service, Mobile, and Gateway Explained

21 min
Power BI🔥 Expert

Implementing Power BI Dataset Certification and Endorsement Workflows to Establish a Trusted Enterprise Data Catalog

28 min
Power BI🔥 Expert

Mastering DAX Window Functions: RANK, ROWNUMBER, and OFFSET for Advanced Comparative Analysis

27 min

On this page

  • Introduction
  • Prerequisites
  • What Is an Aggregation Function, Really?
  • SUM: The Simple Column Aggregator
  • Syntax
  • A Real Example
  • What SUM Can and Cannot Do
  • COUNT and COUNTA: Counting What's There
  • Syntax
  • A Real Example
  • SUMX: The Iterator That Calculates Before It Sums
  • COUNTX: Counting Rows That Meet an Expression
  • Syntax
  • A Real Example
  • Understanding the Iterator Mental Model
  • Choosing Between SUM/COUNT and SUMX/COUNTX
  • Hands-On Exercise
  • Common Mistakes and Troubleshooting
  • Mistake 1: Trying to Put an Expression Inside SUM
  • Mistake 2: Using COUNT on a Text Column
  • Mistake 3: Forgetting That SUMX Iterates the Entire Table by Default
  • Mistake 4: Nesting SUMX Inside SUMX Unnecessarily
  • Mistake 5: Confusing Measures with Calculated Columns
  • Summary and Next Steps
  • Syntax
  • The Classic Example: Revenue from Quantity × Price
  • Going Further: Conditional Logic Inside SUMX
  • COUNTX: Counting Rows That Meet an Expression
  • Syntax
  • A Real Example
  • Understanding the Iterator Mental Model
  • Choosing Between SUM/COUNT and SUMX/COUNTX
  • Hands-On Exercise
  • Common Mistakes and Troubleshooting
  • Mistake 1: Trying to Put an Expression Inside SUM
  • Mistake 2: Using COUNT on a Text Column
  • Mistake 3: Forgetting That SUMX Iterates the Entire Table by Default
  • Mistake 4: Nesting SUMX Inside SUMX Unnecessarily
  • Mistake 5: Confusing Measures with Calculated Columns
  • Summary and Next Steps