DAX - ALLEXCEPT vs ALL+VALUES - powerbi

In this video:
https://youtu.be/teYwjHkCEm0
It is said that ALLEXCEPT is not the same as ALL and VALUES. Further he says that - for filter context having CountryRegion, it makes no difference. But if there was a filter on Continent then the both are not equivalent. What exactly is happening in case of Continent?

When the only existing filter is on Customer[Continent] then the
ALLEXCEPT( Customer, Customer[CountryRegion] )
simply removes all the existing filters from the Customers table.
The
ALL( Customer ),
VALUES( Customer[CountryRegion] )
first saves the VALUES( Customer[CountryRegion] ), that are in the subset of Customer table resulting from the filter on Continent (that's to say the CountryRegions of the currently selected continents), then ALL( Customer ) filter modifier removes the existing filter on the whole Customer table and after that the VALUES( Customer[CountryRegion] ) filter that was evaluated before is applied. The result is that the CountryRegion is "Cross-filered" by the Continent.
this is also explained in this article Using ALLEXCEPT Versus ALL and-VALUES

Related

DAX syntax - Countrows using allexcept filter

I am using three different measures in the same visual (clustered column chart), but in one of the measures I want to leave out the filter which is used in the other measures. That's why I can't use filter on visual because in one of the measures I don't want this to be used.
I am counting rows, a specific number in 'x_channel' column, but I only want to count rows that 'does not contain "3-"' from column "associate.name" in the same table (TICKET).
How do I add this filter in the following syntax:
E-post = CALCULATE(COUNTROWS(TICKET), TICKET[x_channel]=2, USERELATIONSHIP(DIM_DATO[Opprettet], TICKET[Created]))
I think the syntax should be something like this:
E-post = CALCULATE(COUNTROWS(TICKET), TICKET[x_channel]=2 && ALLEXCEPT(TICKET, TICKET[ASSOCIATE.name]="3-"), USERELATIONSHIP(DIM_DATO[Opprettet], TICKET[Created]))
Thank you!
Usage of ALLEXCEPT is totally different. According to the docs and dax.guide
ALLEXCEPT - Returns all the rows in a table except for those rows that are affected by the specified column filters.
So with this function, you can manipulate filter context to remove all filters from the given table but still keep filters from the column provided to ALLEXCEPT function.
The syntax would be like
Measure =
CALCULATE(
COUNTROWS( TABLE1 ),
ALLEXCEPT( TABLE2, TABLE2[ColumnName] )
)
For your case, try this one:
E-post =
CALCULATE(
COUNTROWS( TICKET ),
TICKET[x_channel] = 2,
TICKET[ASSOCIATE.name] <> "3-",
USERELATIONSHIP( DIM_DATO[Opprettet], TICKET[Created] )
)
or you can use FILTER with ALL and then COUNTROWS as follows
E-post =
CALCULATE(
COUNTROWS(,
FILTER(
ALL( TICKET ),
TICKET[x_channel] = 2 && TICKET[ASSOCIATE.name] <> "3-"
)
),
USERELATIONSHIP( DIM_DATO[Opprettet], TICKET[Created] )
)
In fact, the FILTER with ALL is used under the hood in the first scenario.

RANKX does not give the correct result

I need to create a measure (not column) that would rank users based on value.
Here I am trying to use RANKX function:
ranking =
RANKX(
ADDCOLUMNS(
SUMMARIZE(dim_User,
dim_User[UserID],
dim_User[FirstName]
),
"Ttl Trans", [Ttl Transactions]
)
, [Ttl Transactions]
)
Same result using:
rating2 =
RANKX(
SUMMARIZE(dim_User,
dim_User[FirstName]
), [Ttl Transactions]
)
Tried this way:
rating1 =
RANKX(
SUMMARIZE(dim_User,
dim_User[FirstName],
"Trans",[Ttl Transactions]
), [Trans]
)
But gives me an error:
The value for 'Trans' cannot be determined. Either the column doesn't exist, or there is no current row for this column.
I also tried using COUNTROWS() function, but also no success.
It seems like it works if I use a table, not a table expression.
What am I missing here?
UPDATE:
Adding ALL(dim_User) still giving me 1
ranking =
RANKX(
ADDCOLUMNS(
SUMMARIZE(ALL(dim_User),
dim_User[UserID],
dim_User[FirstName]
),
"Ttl Trans", [Ttl Transactions]
)
, [Ttl Transactions]
)
UPDATE
No matter what user I select, in a rating in a card is always 1.
When you write a measure, it is evaluated within its local filter context. In particular, dim_User is filtered by FirstName within your measure and is, therefore, ranking Ttl Trans only compared to other users with the same FirstName.
Since you are ranking based on user, you want to remove the filter context introduced by the visual in order to get the ranking you expect. I'd suggest replacing the table argument dim_User with ALL(dim_User) to remove all filtering on that table or -- more likely the option you want -- with ALLSELECTED(dim_User) to remove the local filter context introduced by the visual while maintaining any filter context from slicers or page-level filters.
For your card, you'll need to simulate the filter context that exists in the table:
UserRanking =
VAR SelectedUser = SELECTEDVALUE ( dim_User[Name_FirstLast] )
RETURN
CALCULATE (
RANKX ( ALL ( dim_User ), [Ttl Transactions] ),
dim_User[Name_FirstLast] = SelectedUser
)

DAX TREATAS filtering by another table to get sales of all products on promotion

How to filter all products on promotion? Say we have two tables Sales and Budget without physical relationship. Here model is simplified and let's assume that it is the case, we cannot create physical relationship. We have to use virtual relationship.
We can see summary:
The two first columns are of the Sales table. The third column BudgetTreats is a measure:
BudgetTreatas =
CALCULATE (
SUM ( Budget[amount] ),
TREATAS (
VALUES ( Sales[id] ),
Budget[id]
)
)
Now I would like to resolve two things:
How to make a slicer to filter out only the products (id) which have BudgetTreatas?
How to create a measure for calculating sales but only for products which have a budget? So analogous measure as BudgetTreatas presented above.
And of course sample data: DAX TREATS.pbix
I posted an answer to my question but it is not to show an answer but rather to show working solutions, and give you idea on expected results. I would be grateful for any answer or comments.
References:
The Logic behind the Magic of DAX Cross Table Filtering
Virtual Filters Using TREATAS
How To Use The TREATAS Function - Power BI & DAX
Creating Virtual Relationships Using TREATAS - Advanced Power BI Technique
Measure calculating Sales filtered by ids in Budget table.
Surprisingly this is not working:
//not working:
SalesFilteredByBudget1 =
CALCULATE (
[Sales],
TREATAS ( VALUES ( Budget[id] ), Sales[id] )
)
It seems we need an extra table. If we add to the model a Bridge table with all sales id and connect it to Sales table on id (without connecting it to Budget table!) we may resolve the issue.
//works:
SalesFilteredByBudget2 =
CALCULATE (
[Sales],
TREATAS ( VALUES ( Budget[id] ), Bridge[id] )
)
So it seems filters propagate further from tables used in TREATAS( VALUES on the tables connected by physical relations.
If we want to make a measure without Bridge table we can make extra table as a table variable.
// works:
SalesFilteredByBudget3 =
VAR Lineage =
TREATAS ( VALUES ( Budget[id] ), Sales[id] )
VAR tbl =
CALCULATETABLE ( Sales, KEEPFILTERS ( Lineage ) )
VAR result =
CALCULATE ( SUMX ( tbl, [amount] ) )
RETURN
result

What exactly does Allexcept() Function return in expanded tables? And why?

The function Allexcept is descriped quite the same both in "Definitive Guide to DAX":
"You can also specify one entire table instead of all the columns of a table that is part of the expanded table"(P430)
and on dax.guide:
"ALLEXCEPT removes filters from the expanded version of Sales, which includes all the tables that can be reached through a many-to-one relationship starting from Sales."
https://www.sqlbi.com/articles/managing-all-functions-in-dax-all-allselected-allnoblankrow-allexcept/
And they all imply that Allexcept returns a table when not used as a top function in Calculate as filter arguments, just like what All() does, while in my practice it is something different:
Consider a single-table model like:
Name Datetime
John 2018/6/25
James 2018/7/7
Smith 2018/7/27
Smith 2018/11/21
Smith 2018/6/9
Mary 2019/1/31
Emily 2018/8/20
John 2018/6/9
Mary 2018/11/11
John 2018/8/21
with a related calendar using Calendarauto() with a calculated column:
YearMonth = FORMAT('Date'[Date],"yyyymm")
Now I want to know how many YearMonth does every Name correspond to, which should be like this:
Name MonthNum
John 2
James 1
Smith 3
Mary 2
Emily 1
With knowledge of expanded tables and Allexcept(and how context transition works), I used formula like this:
Wrong =
ADDCOLUMNS (
VALUES ( Data[Name] ),
"MonthNum", CALCULATE (
DISTINCTCOUNT ( 'Date'[YearMonth] ),
CALCULATETABLE ( ALLEXCEPT ( Data, Data[Name] ) )
)
)
The result turns out to be:
Name MonthNum
John 5
James 5
Smith 5
Mary 5
Emily 5
But I DO KNOW how to make it right, by adding "Data," after Calculatetable:
Correct =
ADDCOLUMNS (
VALUES ( Data[Name] ),
"MonthNum", CALCULATE (
DISTINCTCOUNT ( 'Date'[YearMonth] ),
CALCULATETABLE ( Data, ALLEXCEPT ( Data, Data[Name] ) )
)
)
Please explain the exact reason why Wrong Version does not behave as expected.
interesting question. I am no dax expert, but I'll give this a try.
First, from my understanding, ALL, ALLSELECTED... do not return anything by themselves, they simply clear filters. Not sure, if it's relevant, but might be worth mentioning.
Why doesn't the wrong column work? It has a lot to do with the relationship. If you simply connected data and calendar table, it created a one-way relationship from the calendar to data-table.
If you change it to both way relationship (for scientific purposes only), even the "wrong" column formula will work, because the engine can keep the name filter active.
Now let's look why correct one works, but the other fails in your case.
Let's isolate the calculate tables first.
The correct one - correct_calc = CALCULATETABLE ( Sheet1, ALLEXCEPT ( Sheet1, Sheet1[Name] ) )
returns
while wrong one - wrong_calc = CALCULATETABLE ( ALLEXCEPT ( Sheet1, Sheet1[Name] ) )
returns
With these tables in mind, I would guess, that the correct one keeps "name" filters, as they exist within the calculated table, so the engine sees for every "name" only part of the table.
The wrong one on the other hand just keeps all dates, regardless of the "names" filter, as the "name" values do not come into consideration at all, because there is no relationship between the VALUES ( Data[Name] ) and table you are making the calculation on ie CALCULATETABLE ( ALLEXCEPT ( Data, Data[Name] ) ).
While writing the answer, I've realized, that it's not an exact reason as you've requested so my apologies.
I did a lot of tests to find how exactly Allexcept() behaves, and here's my conclusion:
Allexcept() has 2 different behavior, just like All():
1.as a "removefilter", this way it removes all filters from the columns which are not excluded from the expanded table, but by itself it does not return anything;
2.returns a "special" expanded table which only contains those columns that are not excluded from the original expanded table.In this case, the result table still act like an expanded table whenever possible.
Behavior 1 is too clear to be explained.To activate this behavior, just use allexcept() as a top function in Calculate() or Calculatetble() as a filter argument.
Behavior 2 is far more complicated to prove and understand.
This formula proves that Allexcept() can return a table and that the result table is incomplete(using DAXStudio to test the result is highly recommended):
EVALUATE
GENERATE (
VALUES ( Data[Name] ),
CALCULATETABLE ( ALLEXCEPT ( Data, Data[Name] ) )
)
This one shows that Allexcept() can return a table by itself when required:
EVALUATE
GENERATE ( VALUES ( Data[Name] ), ALLEXCEPT ( Data, Data[Name] ) )
This one shows that the result table returned by Allexcept() is an expanded one:
EVALUATE
CALCULATETABLE ( 'Date', CALCULATETABLE ( ALLEXCEPT ( Data, Data[Name],Data[Datetime],Data[Type] ) ) )
And the last formula shows that when used as a table returner, Allexcept() ignores any filter argument on the original expanded table, this include both the excluded columns and the ones not excluded, which means that all filters on the original expanded table are useless:
CALCULATETABLE (
'Date',
CALCULATETABLE (
ALLEXCEPT ( Data, Data[Name] ),
Data[Name] = "Tom",
'Date'[YearMonth] ="2018-1-1"
)
)
Please comment if you have any advice!

Filtered Running Total

I am trying to get a running total of a count value in a table, but I need to have the filters I created to apply.
Basically I have 2 tables.
Table one is a user table which contains the user email (useremail) address and the user country (usercountry)
Table two contains the user email (useremail) and a date when they signed an agreement (Created)
I created a measure like this, which gets the user email from the signup table and gives me the running total, but when I apply a filter to the report, the sign up count does not change. It completely ignores the filter
Sign ups =
CALCULATE (
DISTINCTCOUNT( 'SignUps'[useremail] ),
FILTER (
ALLselected ( 'SignUps' ),
'SignUps'[Created] <= MAX ( 'SignUps'[Created] )
)
)
There is a relationship between the two tables where users(useremail) matches sign ups(useremail) One to One and cross filter both directions
Basically the chart below never changes regardless of the usercountry I filter by
Sign Up Chart.
Any idea how I can do this?
You won't need ALLSELECTED unless you are showing visual total.
Remove ALLSELECTED and just pass a table so it can be filtered using your slicer.
Sign ups =
CALCULATE (
DISTINCTCOUNT ( 'SignUps'[useremail] ),
FILTER (
'SignUps',
'SignUps'[Created] <= MAX ( 'SignUps'[Created] )
)
)
Read ALLSELECTED