TOPN()
Learn how TOPN returns the top (or bottom) N rows of a table by a given expression.
TOPN()
TOPN() returns a table containing the top (or bottom) N rows, ranked by a given expression — the DAX equivalent of "show me the top 10."
TOPN(
N Value,
Table,
OrderBy Expression,
[Order]
)Basic Example
Top 5 Products =
TOPN(
5,
ALL(DimProduct),
[Total Sales]
)All Products (ranked by Total Sales, descending)
|
+-- Tire A 50,000
+-- Tire B 42,000
+-- Helmet A 18,000
+-- Lock A 12,000
+-- Pump A 9,500
|
Top 5 Products = these 5 rowsBecause TOPN() returns a table, it's typically wrapped in CALCULATE() to restrict a measure to just those top rows, or used inside another table function.
TOPN Inside CALCULATE
Top 5 Sales =
CALCULATE(
[Total Sales],
TOPN(
5,
ALL(DimProduct),
[Total Sales]
)
)This restricts [Total Sales] to only the 5 highest-selling products, regardless of how many products actually exist in the model.
Order: Descending vs. Ascending
Bottom 5 Products =
TOPN(
5,
ALL(DimProduct),
[Total Sales],
ASC
)DESC (default): highest values first -> "top" N
ASC: lowest values first -> "bottom" NTOPN vs. RANKX + FILTER
The same "top N" result can be built by ranking every row and filtering down to the top ranks — TOPN() is the more direct route to the same answer.
Top 5 (via RANKX + FILTER) =
CALCULATE(
[Total Sales],
FILTER(
ALL(DimProduct),
RANKX(ALL(DimProduct), [Total Sales]) <= 5
)
)Top 5 (via TOPN) =
CALCULATE(
[Total Sales],
TOPN(5, ALL(DimProduct), [Total Sales])
)Both return the same result for a clean top-N cutoff. RANKX() combined with FILTER() is worth reaching for instead when the actual rank number needs to be displayed, or when ties need explicit Skip/Dense handling — see RANKX.
Handling Ties at the Cutoff
TOPN() can return more than N rows when there's a tie at the boundary — by default, all tied rows at the cutoff point are included rather than arbitrarily cutting one out.
Requesting Top 3, with a tie at 3rd place:
Tire A 50,000
Tire B 42,000
Helmet A 18,000
Lock A 18,000 <- tied with Helmet A, both includedThis is usually the desired behavior for a "top N" report, but it means the result set isn't guaranteed to be exactly N rows.
Try it live — edit the values or N to create or remove a tie at the cutoff
| Product | Total Sales | Returned? |
|---|---|---|
| Tire A | 50000 | yes |
| Tire B | 42000 | yes |
| Helmet A | 18000 | yes |
| Lock A | 18000 | yes — tied |
| Pump A | 12000 | no |
| Grip Tape | 9500 | no |
Requested top 3, got back 4 rows.
— 1 extra row tied for the last spot at exactly 18000. TOPN doesn't arbitrarily cut one out to force exactly 3 rows — every row tied at the cutoff value comes back. Code consuming this result can't assume an exact row count.
Common Mistakes
Expecting Exactly N Rows
A tie at the cutoff can return more than N rows — code and visuals consuming the result shouldn't assume an exact row count.
Using TOPN Without CALCULATE for a Scalar Result
TOPN() returns a table. Wrap it in CALCULATE() (or another table-consuming function) rather than expecting it to produce a single value directly.
Choosing TOPN When the Rank Value Itself Is Needed
If a visual needs to display "Rank 1, 2, 3..." next to each row, RANKX() is the right tool — TOPN() only filters to the top rows, it doesn't expose a rank number.
Best Practices
- Wrap
TOPN()inCALCULATE()when the goal is a single aggregated result over the top rows. - Use
RANKX()instead when the rank number itself needs to be shown, or when specific tie-handling is required. - Confirm the table argument (typically wrapped in
ALL()) matches the intended comparison scope, the same consideration that applies toRANKX().
Next Steps
Continue learning DAX functions and patterns: