Forum Discussion
How expanded tables work
- 8 years ago
Your confusion lies in the fact that even though an expanded table is a series of left-outer joins of tables from many -> 1, the expanded table still has all the columns of all the tables. And tables are a collection of independent columns. Meaning that a filter on one column does not affect another until after applied to the model. (and even then the impact if from cross filtering rows) Take this code here:
Sum Amount = CALCULATE(SUM(t3Sales[Amount]),t3ProductName[ProductID])
internally, it is written as this:
Sum Amount = CALCULATE ( SUM ( t3Sales[Amount] ), FILTER ( ALL ( t3ProductName[ProductID] ), t3ProductName[ProductID] ) )So it will return all the ProductID's from the t3ProductName column. But the table also has a filter on t3Sales[ProductID] because you put it on the rows which when combined filters down the t3Sales table to just where t3Sales[ProductID] = 100 for row 1, and so on for rest of the table. Grand total has no filter on t3Sales[ProductID] and only has the above filter on tsProductName[ProductID] column which returns all values, so you get the correct grand total.
next is your Sum Amount2
Sum Amount2 = CALCULATE(SUM(t3Sales[Amount]),t3Sales[ProductID])
which internally is rewritten as:
Sum Amount2 = CALCULATE ( SUM ( t3Sales[Amount] ), FILTER ( ALL ( t3Sales[ProductID] ), t3Sales[ProductID] ) )So, even though you put t3Sales[ProductID] on the rows, since you also referenced that column as a filter argument to CALCULATE, the table row filter is overridden by the above FILTER statement which returns all ProductID for t3Sales for every row which is why you get the grand total amount for every row in table. Difference from Sum Amount is now there is no filter on the t3ProductName[ProductID].
Make sense?
- 8 years ago
"Context Transition" refers to moving a column filter from row contex to filter context.
"Modify filter context" means just that. When you have columns on the rows, columns, filter area, slicers of report that is the initial filter context. Either row context transition or arguments to 'CALCULATE' may change ( or modify) that filter context.
Well, I have t3Sales[ProductID] in both tables, that I am putting to test. However interestingly, if I change t3Sales[ProductID] to t3ProductName[ProductID] in the last visual, I get correct results. Getting totally confused :(
Here is my test pbix file Expanded table test .
Your confusion lies in the fact that even though an expanded table is a series of left-outer joins of tables from many -> 1, the expanded table still has all the columns of all the tables. And tables are a collection of independent columns. Meaning that a filter on one column does not affect another until after applied to the model. (and even then the impact if from cross filtering rows) Take this code here:
Sum Amount = CALCULATE(SUM(t3Sales[Amount]),t3ProductName[ProductID])
internally, it is written as this:
Sum Amount =
CALCULATE (
SUM ( t3Sales[Amount] ),
FILTER ( ALL ( t3ProductName[ProductID] ), t3ProductName[ProductID] )
)So it will return all the ProductID's from the t3ProductName column. But the table also has a filter on t3Sales[ProductID] because you put it on the rows which when combined filters down the t3Sales table to just where t3Sales[ProductID] = 100 for row 1, and so on for rest of the table. Grand total has no filter on t3Sales[ProductID] and only has the above filter on tsProductName[ProductID] column which returns all values, so you get the correct grand total.
next is your Sum Amount2
Sum Amount2 = CALCULATE(SUM(t3Sales[Amount]),t3Sales[ProductID])
which internally is rewritten as:
Sum Amount2 =
CALCULATE (
SUM ( t3Sales[Amount] ),
FILTER ( ALL ( t3Sales[ProductID] ), t3Sales[ProductID] )
)So, even though you put t3Sales[ProductID] on the rows, since you also referenced that column as a filter argument to CALCULATE, the table row filter is overridden by the above FILTER statement which returns all ProductID for t3Sales for every row which is why you get the grand total amount for every row in table. Difference from Sum Amount is now there is no filter on the t3ProductName[ProductID].
Make sense?
- gvg8 years agoPost Prodigy
Yes, this makes sense. Thanks!
- gvg8 years agoPost Prodigy
Well, I am still a little confused. Let's break this all down in small steps for Sum Amount2 for the first value. My understanding is that before CALCULATE starts its job
1. The expanded table is filtered on t3Sales{ProductID]=100 since this field is in the visual. Thus our expanded table looks like this:
2. CALCULATE starts evaluating its filter. This FILTER function sees the table shown in step 1.
3. Since FILTER includes ALL as per your description, the expanded table gets expanded to the original like this:
Or does it expand to this only:
4. CALCULATE begins interpreting the filtered expanded table, which in fact is the whole (?) table.
5. CALCULATE makes context transition, i.e. filters the expanded table with t3Sales[ProductID]=100 like this:
6. Sums the Amount. Shouldn't it arrive at 50?
- mattbrice8 years agoSolution Sage
First, in your actual data in t3Sales, there are two rows with ProductID = 300 & Amount = 50 which is where the total value of 215 comes from. You don't show it in your screenshots.
Second, the order of your logic is not quite correct. CALCULATE does the following:
- Create a new filter context by cloning the existing one.
- Move current rows in the row context to the new filter context one by one and apply blocking semantics against all previous tables.
- Evaluate each setfilter argument in the old filter context and then add setfilter tables to the new filter context one by one and apply blocking semantics against all tables that exist in the new filter context before the first setfilter table is added.
- Evaluate the first argument in the newly constructed filter context.
This means the filter context is constructed prior to being applied to the data tables - not during. So the table itself doesn't expand and contract per your steps - the only thing that changes are what filters are on columns.
1. The filter context has: a filter on the column t3Sales[ProductID] of t3Sales[ProductID] = 100. (no impact to table yet)
2. CALCULATE triggers creation of new filter context by cloning existing which in this case is the filter in step 1.
3. CALCULATE evaluates its setfilter argument which is expanded to this:
FILTER ( ALL ( t3Sales[ProductID] ), t3Sales[ProductID] )
this FILTER iterates over all distinct values in the column, with boolean expression being true for all of them - and therefore returns all distinct values from column t3Sales[ProductID]. Also, since this is the same column as step 1, this new filter blocks(removes) step 1 and replaces it in the filter context with this new one (again, all distinct values for column t3Sales[ProductID].
4. CALCULATE evaluates the first argument 'SUM ( t3Sales[Amount] )' by applying context we ended up with in step 3 to the t3Sale table. Since after being applied filter context returns all rows, we end up with a value of 215.(and will for all other rows in table).
And I would like to point out a couple more things. First when putting t3Sales[ProductID] on the rows of the table, that is a filter context, not a row context. There are only two places to generate a row context. First with a calculated column there exists a row context. Second is programatically with an iterator function. Both are transitioned from row to filter context by use of CALCULATE or some other table function like FIRSTNONBLANK, LASTDATE, etc.
But again putting something on rows, columns, page/report filter area are NOT row contexts. They are filter contexts.
Any clearer? Clear as mud?