Start free
Back to blog

HASONEVALUE vs ISINSCOPE in DAX: Fix Matrix Totals

A tactile editorial typesetting bench comparing two precision instruments for identifying hierarchy level and visible-value count

HASONEVALUE and ISINSCOPE answer different
questions in DAX:

  • HASONEVALUE ( Column ) asks whether filter context
    contains exactly one distinct value.
  • ISINSCOPE ( Column ) asks whether the column is the
    active grouping level in the current hierarchy.

They can both return TRUE on a detail row. They diverge at subtotals,
grand totals, and under slicers. Use ISINSCOPE to control
matrix-level behavior; use HASONEVALUE when the business
rule truly depends on one visible value.

The shortest comparison

Given a matrix:

Category
  Subcategory

At a Subcategory row:

ISINSCOPE ( Product[Subcategory] )

is TRUE because Subcategory is the current grouping level.

HASONEVALUE ( Product[Subcategory] )

is also often TRUE because that row contains one subcategory.

At a Category subtotal,
ISINSCOPE ( Product[Subcategory] ) is FALSE. But
HASONEVALUE ( Product[Subcategory] ) can still be TRUE if
the current category has only one subcategory or a slicer leaves only
one visible.

That difference is why matrix logic built with
HASONEVALUE can break unexpectedly.

Use ISINSCOPE for
hierarchy-aware measures

Suppose a measure should calculate percent of parent:

Percent of Parent =
SWITCH (
    TRUE (),
    ISINSCOPE ( Product[Subcategory] ),
        DIVIDE (
            [Sales Amount],
            CALCULATE (
                [Sales Amount],
                ALLSELECTED ( Product[Subcategory] )
            )
        ),
    ISINSCOPE ( Product[Category] ),
        DIVIDE (
            [Sales Amount],
            CALCULATE (
                [Sales Amount],
                ALLSELECTED ( Product[Category] )
            )
        ),
    1
)

The formula asks which level Power BI is currently grouping, then
selects the correct denominator.

Microsoft
defines ISINSCOPE
as TRUE when the specified column is
the level in a hierarchy, and its official example uses the function for
percentage of parent.

See the complete denominator discussion in Power BI percent of
total
.

Use HASONEVALUE
for a single-value requirement

Suppose a conversion is valid only when exactly one currency is
visible:

Converted Sales =
IF (
    HASONEVALUE ( Currency[CurrencyCode] ),
    [Sales Amount] * [Selected Exchange Rate],
    BLANK ()
)

The calculation does not care whether Currency appears on a matrix
axis. It cares whether one currency is present in filter context.

That one value might come from:

  • a matrix row;
  • a slicer;
  • a page filter;
  • relationship propagation; or
  • another column in the same table.

This is a HASONEVALUE question.

Why a
slicer changes HASONEVALUE at the grand total

Select one Category in a slicer.

At the matrix grand total:

HASONEVALUE ( Product[Category] )

can be TRUE because the slicer leaves one visible category.

But:

ISINSCOPE ( Product[Category] )

is FALSE because the grand total is not grouped by Category.

If your intent is “hide this measure at the grand total,” use
ISINSCOPE.

If your intent is “calculate only when one category is selected
anywhere,” use HASONEVALUE.

HASONEVALUE and
SELECTEDVALUE

These patterns are conceptually related:

IF (
    HASONEVALUE ( Product[Category] ),
    VALUES ( Product[Category] )
)
SELECTEDVALUE ( Product[Category] )

SELECTEDVALUE is the convenient scalar form. It returns
its alternate result when the context has zero or multiple distinct
values.

If a selection unexpectedly returns blank, count values
explicitly:

Visible Category Count =
COUNTROWS ( VALUES ( Product[Category] ) )

Then use the SELECTEDVALUE troubleshooting
guide
.

A common wrong-total pattern

This formula is intended to calculate an average at detail rows and a
custom result at totals:

Result =
IF (
    HASONEVALUE ( Product[Subcategory] ),
    [Detail Result],
    [Total Result]
)

It fails when a Category subtotal happens to contain one visible
Subcategory. DAX chooses [Detail Result] even though the
visual is at the Category level.

Use:

Result =
SWITCH (
    TRUE (),
    ISINSCOPE ( Product[Subcategory] ), [Subcategory Result],
    ISINSCOPE ( Product[Category] ), [Category Result],
    [Grand Total Result]
)

The branch now follows visual structure, not accidental
cardinality.

Why
ISINSCOPE can be FALSE when one value is visible

ISINSCOPE does not mean “filtered.”

A Category slicer can restrict the report to Bikes while a card
displays Sales. In the card:

  • HASONEVALUE ( Product[Category] ) may be TRUE;
  • ISINSCOPE ( Product[Category] ) is FALSE.

Category affects the card, but it is not a grouping level in that
evaluation.

Microsoft’s
information-function reference
distinguishes
HASONEVALUE, ISFILTERED,
ISCROSSFILTERED, and ISINSCOPE. Choose the
predicate that matches the question.

When to use ISFILTERED
instead

Use ISFILTERED when you need to know whether a column or
table is directly filtered:

Category Filter Message =
IF (
    ISFILTERED ( Product[Category] ),
    "Category filtered",
    "All categories"
)

It does not require exactly one value and does not detect hierarchy
level.

Use ISCROSSFILTERED when related-table filters should
count as filtering.

Do not substitute these functions based on which one makes a
screenshot look correct. Name the semantic question first.

Debug all three states side
by side

Create:

Debug Has One Category =
HASONEVALUE ( Product[Category] )
Debug Category In Scope =
ISINSCOPE ( Product[Category] )
Debug Category Count =
COUNTROWS ( VALUES ( Product[Category] ) )

Place them in the matrix and test:

  1. a detail row;
  2. a parent subtotal;
  3. the grand total;
  4. a one-value slicer;
  5. a multi-value slicer;
  6. a parent with only one child.

The last state is especially important because it exposes formulas
that confuse cardinality with hierarchy.

Totals still recalculate

ISINSCOPE helps you select a branch, but it does not
make totals additive. Each branch is still evaluated in the filter
context of that row or subtotal.

If the desired total should sum a detail expression:

Total of Detail Results =
SUMX (
    VALUES ( Product[Subcategory] ),
    [Detail Result]
)

Use this only if summing detail results matches the business
definition. Read why DAX grand
totals recalculate
before forcing a visible-row sum.

Frequently asked questions

Is HASONEVALUE the same as
ISINSCOPE?

No. HASONEVALUE tests whether one distinct value is
visible. ISINSCOPE tests whether a column is the active
hierarchy level in the current query.

Which function
should I use for matrix totals?

Usually ISINSCOPE, because detail, subtotal, and
grand-total behavior depends on the matrix grouping level. Use
HASONEVALUE only if one visible value is the actual
rule.

Why is HASONEVALUE true at
the total?

A slicer, page filter, relationship, or the data itself may leave
exactly one distinct value even though the visual is at its grand
total.

Where can I test the
difference?

Build a two-level hierarchy in the DAX
playground
. Add the three debug measures and test parent groups with
one child and several children.

Done reading?

Put it into reps — pick a challenge.

Start practicing More posts