DAX Deep Dive on FILTERS(), VALUES(), & ALLSELECTED()
Description
Comprehensive analysis of FILTERS(), VALUES(), and ALLSELECTED() functions in DAX with a focus on Weighted Turnover Calculation and Weighted Average Turnover Calculation.
Understanding FILTERS(), VALUES(), and ALLSELECTED() in DAX
Tool: Languages Advisor
Created: 03/24/2024
Prompt
Within a viz, I want to remove all context from a table except a few fields and calculated weighted average (within region/subregion/facility, find turnover at each address, and calculate wt avg turnover based on total appts at each address.)
Hierachary: Region->SubRegion->Facility->Address->LocationCode
I want to know what is the difference between:
1.WtTurnover New =
VAR lowerbound=0.008
VAR upperbound=0.13
VAR rooms=CALCULATETABLE(
FILTER(
ADDCOLUMNS(
VALUES(āRoomsā[Rooms Address])
,āTā,[Turnover New]
,āAā,[Total Appt by Address New]
)
,lowerbound<=[Turnover New]&&[Turnover New]<=upperbound
)
,ALLSELECTED('Rooms ')
,FILTERS(āRoomsā[Rooms Region])
,FILTERS('Rooms '[Rooms Sub Region])
,FILTERS('Rooms '[Rooms Facility Name])
)
VAR numerator=SUMX(rooms,[A]*[T])
VAR denominator=SUMX(rooms,[A])
RETURN DIVIDE(numerator,denominator,BLANK())
2.WtTurnover New 2 =
VAR lowerbound=0.008
VAR upperbound=0.13
VAR rooms=CALCULATETABLE(
FILTER(
ADDCOLUMNS(
VALUES(āRoomsā[Rooms Address])
,āTā,[Turnover New]
,āAā,[Total Appt by Address New]
)
,lowerbound<=[Turnover New]&&[Turnover New]<=upperbound
)
,ALLSELECTED(āRoomsā)
,VALUES(āRoomsā[Rooms Region])
,VALUES(āRoomsā[Rooms Sub Region])
,VALUES(āRoomsā[Rooms Facility Name])
)
VAR numerator=SUMX(rooms,[A]*[T])
VAR denominator=SUMX(rooms,[A])
RETURN DIVIDE(numerator,denominator,BLANK())
Option 1 returned what I want.
I donāt understand why at the Location Code level, option 2 returned a different results(Highlighted yellow, it returned the turnover calculated at address level, but I didnt add VALUES(Rooms Address) within option 2 and I thought allselected() would remove context from address and location code and option 2 would behave exactly as option 1.
Thanks. Any help is appreciated.
Based on your question, it seems there is a fundamental misunderstanding between how FILTERS()
and VALUES()
functions operate, and ALLSELECTED()
function.
The FILTERS()
function in DAX returns the set of filters applied on a column, while VALUES()
function returns a one-column table containing the distinct values in a column.
Difference between Option 1 and Option 2
The key difference between the two calculations is whether they preserve the entire context of user selections (Option 2) or only a subset of those selections (Option 1). Option 1 uses FILTERS()
to restrict the context for each of the columns Rooms Region, Rooms Sub Region, and Rooms Facility Name. In contrast, Option 2 uses VALUES()
instead of FILTERS()
, which allows all distinct values of the columns preserving only the filters directly applied by the user.
Reason for difference in results
Reason why the results from the two calculations do not match is how ALLSELECTED()
is working in both options. ALLSELECTED()
removes filters from the column in the entire table and retains the context of user selection, which includes the values of other columns, such as Address and Location Code.
In Option 1, even though you used ALLSELECTED('Rooms')
, the filters for Region, Subregion, and Facility Name are explicitly added back due to FILTERS()
. Therefore, it will calculate the weighted average turnover for each individual Region->SubRegion->Facility->Address.
However, in Option 2, ALLSELECTED('Rooms')
is removing all the filters from the Rooms table but VALUES()
does not add back the filters for individual columns (Region, Subregion, Facility Name). Therefore, the weighted average turnover at the Address level is returned because the context of Address is preserved due to user selection and added back due to VALUES()
.
Conclusion
To make Option 2 behave exactly as Option 1, you would have follow the method used in Option 1, i.e., use FILTERS()
instead of VALUES()
. This would mean that instead of preserving all the distinct values, you only need to consider the specific filters applied by the user.
Weighted Turnover Calculation in DAX Code
Tool: Code Explainer
Created: 03/24/2024
Prompt
Hierachary: Region->SubRegion->Facility->Address->LocationCode
I want to know what is the difference between:
1.WtTurnover New =
VAR lowerbound=0.008
VAR upperbound=0.13
VAR rooms=CALCULATETABLE(
FILTER(
ADDCOLUMNS(
VALUES(āRoomsā[Rooms Address])
,āTā,[Turnover New]
,āAā,[Total Appt by Address New]
)
,lowerbound<=[Turnover New]&&[Turnover New]<=upperbound
)
,ALLSELECTED('Rooms ')
,FILTERS(āRoomsā[Rooms Region])
,FILTERS('Rooms '[Rooms Sub Region])
,FILTERS('Rooms '[Rooms Facility Name])
)
VAR numerator=SUMX(rooms,[A]*[T])
VAR denominator=SUMX(rooms,[A])
RETURN DIVIDE(numerator,denominator,BLANK())
This code snippet is written in DAX (Data Analysis Expressions), a formula language used in Power BI. The code calculates a 'Weighted Turnover' for a subset of a table named 'Rooms'. Now let's break down the code.
Hierarchy
Region->SubRegion->Facility->Address->LocationCode
shows a hierarchical relationship, indicating that eachRegion
containsSubRegions
, eachSubRegion
contains multipleFacilities
, eachFacility
has anAddress
, and eachAddress
has aLocationCode
.Variables Declarations
VAR lowerbound=0.008
,VAR upperbound=0.13
are variable declarations. These variables are thresholds used later in the script.Calculation of 'rooms' Table
The
rooms
variable is a calculated table, using theCALCULATETABLE
function, which evaluates a table expression in a context modified by filters. InsideCALCULATETABLE
, a new temporary table is created usingADDCOLUMNS
, which appends calculated fields namely "T" (Turnover New) and "A" (Total Appt by Address New) to the original 'Rooms' table.The
FILTER
function insideCALCULATETABLE
filters this newly created table to include only rows where 'Turnover New' is betweenlowerbound
andupperbound
.The 'Rooms' table is then further filtered to consider only the current selections made by the user for 'Region', 'SubRegion', and 'Facility Name' using
ALLSELECTED
andFILTERS
.Calculation of 'numerator' and 'denominator'
The
numerator
is the sum of the product of columns 'A' and 'T' of therooms
table, computed using theSUMX
function.The
denominator
is the sum of 'A' values in therooms
table.Return Statement
The final line,
RETURN DIVIDE(numerator,denominator,BLANK())
, returns the division ofnumerator
anddenominator
. Ifdenominator
is zero, instead of returning an error, it returns aBLANK()
.Therefore, the function computes a particular type of weighted average, where turnover is considered only if it falls within certain bounds and corresponds to currently selected context filters.
Weighted Turnover Calculation in DAX
Tool: Code Explainer
Created: 03/24/2024
Prompt
2.WtTurnover New 2 =
VAR lowerbound=0.008
VAR upperbound=0.13
VAR rooms=CALCULATETABLE(
FILTER(
ADDCOLUMNS(
VALUES(āRoomsā[Rooms Address])
,āTā,[Turnover New]
,āAā,[Total Appt by Address New]
)
,lowerbound<=[Turnover New]&&[Turnover New]<=upperbound
)
,ALLSELECTED(āRoomsā)
,VALUES(āRoomsā[Rooms Region])
,VALUES(āRoomsā[Rooms Sub Region])
,VALUES(āRoomsā[Rooms Facility Name])
)
VAR numerator=SUMX(rooms,[A]*[T])
VAR denominator=SUMX(rooms,[A])
RETURN DIVIDE(numerator,denominator,BLANK())
This code snippet is written in Data Analysis Expressions (DAX), a formula language used mainly with Power BI Desktop and Power Pivot in Excel. The code calculates a weighted turnover. Here's a detailed explanation:
1. Code Analysis:
The line of code VAR lowerbound=0.008
and VAR upperbound=0.13
sets two variables lowerbound
and upperbound
respectively.
rooms
is declared as a variable which holds a table. The CALCULATETABLE
function generates it by filtering and adding columns to 'Rooms', based on multiple filtering conditions.
numerator
and denominator
are variables representing the numerator and denominator used to calculate the turnover.
The DIVIDE()
function is used to divide the numerator by denominator, returning a blank value if the denominator equals zero.
2. Key Concepts:
- Variables in DAX allow results of expressions to be stored in-memory for subsequent use.
- CALCULATETABLE function in DAX takes a table or an expression that returns a table and further filters that table.
- ADDCOLUMNS is used to calculate results row by row and add these as new columns.
- VALUES function creates a one-column table that contains unique values from the specified table column.
- FILTER function is used to filter a table and keep rows that meet the specified criteria.
- ALLSELECTED removes filters on columns in the same table as the column being evaluated and retains all other filters.
- SUMX returns a sum of expressions evaluated for each row in a table.
3. Expanded Breakdown of the Code:
VAR lowerbound=0.008
VAR upperbound=0.13
The above part of the code declares two variables and assigns them values.
VAR rooms=CALCULATETABLE(
FILTER(
ADDCOLUMNS(
VALUES(āRoomsā[Rooms Address])
,āTā,[Turnover New]
,āAā,[Total Appt by Address New]
)
,lowerbound<=[Turnover New]&&[Turnover New]<=upperbound
)
,ALLSELECTED(āRoomsā)
,VALUES(āRoomsā[Rooms Region])
,VALUES(āRoomsā[Rooms Sub Region])
,VALUES(āRoomsā[Rooms Facility Name])
)
Declared a 'rooms' variable which represents a calculated table constructed from existing 'Rooms', augmented with additional columns and filtered by multiple conditions.
VAR numerator=SUMX(rooms,[A]*[T])
VAR denominator=SUMX(rooms,[A])
The variables numerator and denominator are calculated.
RETURN DIVIDE(numerator,denominator,BLANK())
The result of dividing the numerator by the denominator. If the denominator is zero, it returns BLANK().
4. Alternative Code:
An alternative way to compute the numerator would be to use SUMX(FILTER(rooms, [A] > 0), [A]*[T])
to ensure there are no rows with zero in column A - as multiplying by zero would turn column T's value to zero.
DAX Weighted Average Turnover Calculation
Tool: Code Simplifier
Created: 03/24/2024
Prompt
Within a viz, I want to remove all context from a table except a few fields and calculated weighted average (within region/subregion/facility, find turnover at each address, and calculate wt avg turnover based on total appts at each address.)
Hierachary: Region->SubRegion->Facility->Address->LocationCode
I want to know what is the difference between:
1.WtTurnover New =
VAR lowerbound=0.008
VAR upperbound=0.13
VAR rooms=CALCULATETABLE(
FILTER(
ADDCOLUMNS(
VALUES(āRoomsā[Rooms Address])
,āTā,[Turnover New]
,āAā,[Total Appt by Address New]
)
,lowerbound<=[Turnover New]&&[Turnover New]<=upperbound
)
,ALLSELECTED('Rooms ')
,FILTERS(āRoomsā[Rooms Region])
,FILTERS('Rooms '[Rooms Sub Region])
,FILTERS('Rooms '[Rooms Facility Name])
)
VAR numerator=SUMX(rooms,[A]*[T])
VAR denominator=SUMX(rooms,[A])
RETURN DIVIDE(numerator,denominator,BLANK())
The original code snippet is in DAX (Data Analysis Expressions), a formula language used primarily with Power BI Desktop. Its main purpose is to calculate a weighted average turnover limited to a specific range. The calculation is done in five main steps:
- A table,
Rooms
, is filtered to only include rows where the fieldTurnover New
is between thelowerbound
andupperbound
. - The filters applied to the visuals are maintained.
- The chosen rows'
Turnover New
andTotal Appt by Address New
values are multiplied and the results are summed up to create thenumerator
. - The
Total Appt by Address New
values for all the selected rows are summed up to create thedenominator
. - The
numerator
is divided by thedenominator
to get the weighted average.
To simplify this code, using CALCULATE
instead of CALCULATETABLE
will automatically consider the filters applied to the visuals. Here is the simplified DAX version:
WeightedTurnoverNew =
VAR lowerbound = 0.008
VAR upperbound = 0.13
VAR rooms = ADDCOLUMNS(
FILTER(
VALUES('Rooms'[Rooms Address]),
lowerbound <= CALCULATE([Turnover New]) && CALCULATE([Turnover New]) <= upperbound
),
"T", [Turnover New],
"A", [Total Appt by Address New]
)
VAR numerator = SUMX(rooms,[A]*[T])
VAR denominator = SUMX(rooms,[A])
RETURN DIVIDE(numerator,denominator,BLANK())
Some courses on our Enterprise DNA Platform that might help you further in understanding DAX are "DAX Foundation", "Advanced DAX", and "Mastering DAX Calculations".
Always remember:
- Maintain the code readability.
- Keep the use of variables for better design and to avoid extra calculations.
- Ensure to conduct test cases to validate all operations.