I was ding some DAX exercises and came across this measure:
Average Return on Investment =
DIVIDE (
SUMX (
fact_RoI;
fact_RoI[Return on Investment] * [SumInvestment]
);
SUMX ( fact_RoI;[SumInvestment] )
)
This measure works, but can someone explain to me why they are using a SUMX in the bottom part as well? I tried just using the SumInvestments measure instead and got very wrong result, but I do not understand why.
edit: adding this as requested (sorry, didn't think it was relevant)
SumInvestment =
CALCULATE (
SUM ( fact_Investments[Investment] );
CROSSFILTER (
fact_RoI[Product];
dim_Product[Product];
Both))
SUMX ( fact_RoI;[SumInvestment] ) iterates over the fact_RoI table, however the Measure SumInvestment sums a column from another table (fact_Investments). Thus if you want to obtain a calculation based on the RoI you would need to iterate over it as in the example.
Otherwise the SUM of fact_Investment probably just produces a meaningless result, like: sum all investments regardless of their connection to RoI.
Related
Following are 2 measures:
SUMX ( ALL ( SALES ) , SALES[AMT] )
CALCULATE ( SUMX ( SALES, SALES[AMT] ), ALL (SALES) )
Similarly for the following 2 measures:
SUMX ( FILTER ( SALES, SALES[QTY]>1 ), SALES[QTY] * SALES[AMT] )
CALCULATE ( SUMX ( SALES, SALES[QTY] * SALES[AMT] ), FILTER ( SALES, SALES[QTY]>1 ) )
Both above examples clear the natural filters on the SALES table and perform the aggregation.
I'm trying to understand what is the significance/use case of using either approach maybe in terms of logic or performance?
In DAX you can achieve the same results from different DAX queries/syntax.
So based on my understanding both the DAX provide the same result :
SUMX ( ALL ( SALES ) , SALES[AMT] )
CALCULATE ( SUMX ( SALES, SALES[AMT] ), ALL (SALES) )
And the 1st one is a more concise way to achieve way rather than the 2nd one in all cases/scenarios.
Currently when I tested these out with <100 records in a table ; the performance was the same for both the measures.
But ideally the 1st scenario would be quicker then the 2nd one which we can test out by >1 million record through DAX studio.
Can you please share your thoughts on the same?
The first uses a table function to return the whole sales table and then iterate. The second iterates over the sales table in the context of calculate which removes any filters that were present on the sales table.
SUMX ( ALL ( SALES ) , SALES[AMT] )
CALCULATE ( SUMX ( SALES, SALES[AMT] ), ALL (SALES) )
In these two DAX functions, ALL() is doing two very different things and it is unfortunate the same name was used. In the first one, ALL() is being used as a table function and returns a table. In the second one, ALL() is being used to remove filters and could be replaced with REMOVEFILTERS() (the first one cannot be replaced this same way).
This is a lengthy and detailed topic and I suggest you make a cup of coffee and have a read here: https://www.sqlbi.com/articles/managing-all-functions-in-dax-all-allselected-allnoblankrow-allexcept/
To summarise the article, ALL() and REMOVEFILTERS() are not the same. ALL() can be used where REMOVEFILTERS() is used but not vice versa.
CALCULATE ( SUMX ( SALES, SALES[QTY] * SALES[AMT] ), FILTER ( SALES, SALES[QTY]>1 ) )
This DAX uses calculate to change the filter context and remove any existing filters. The important thing is that it is removing existing filters.
They mainly achieve the same result (most of the time) but there is still more nuance though. In DAX, there are always multiple ways of achieving the same outcome. More importantly, DAX is always dependent on the evaluation context. Writing SUM(SALES[AMT]) can return different numbers depending on context. If it was in table with colour, it would return the sum per colour at each line and a total. If it were by country, it would return a total by country and a total. i.e. the exact same formula returns different results depending on context. In this simplistic example, they are essentially the same though.
The second example would also never be written it this way as you should never filter entire tables (especially fact tables). You would filter the column instead. e.g.
SUMX(
FILTER(VALUES(Sales[Quantity]),
Sales[Quantity]>1), Sales[Quantity] * Sales[SalesAmount]
)
This whole video is an excellent watch but if you watch from 45:33, you can see a good explanation of the difference between removing filters and returning a table which is the essence of your question. You also need to understand expanded tables which is explained earlier in the video. youtube.com/watch?v=teYwjHkCEm0&list=WL&index=2
At the risk of stating the obvious, you are wrapping a function (SUMX) inside a process represented by CALCULATE function.
It is an actual process, which will attempt a context transition.
Beyond the performance implications of forcing extra processing, the answer to your question heavily depends on how and where these measures get injected into the model, as it determines if the context transition would occur.
For reference, here are just some of the relevant SQLBI articles: https://www.sqlbi.com/articles/introducing-calculate-in-dax/
https://www.sqlbi.com/articles/understanding-context-transition-in-dax/
This is kind of similar to my question here, but different enough i think to justify a new question. Looking at the below table, i want to take the total of Direct Expense across all regions, and subtract that from the Americas Expense number only, then total up the result.
I'd like the last column's total to read 17,661, not 54,888. Here is a link to a sample workbook on OneDrive with the above table: https://1drv.ms/u/s!Al7VQqB8RVlWgY4mUYqouesRPNE0qw?e=IiMPnq Any ideas?
Your measure had two issues:
it was missing the context transition, this can be fixed adding
CALCULATE where a context transition is needed
The [Total Direct Expense total for Region (c)] uses ALLSELECTED,
ad it's called inside an iterator. But we can move the measure
before the iteration using a variable instead. (The number 13,703 is wrong)
The measure then becomes
Final Result (a-c) =
VAR TotalExpense = [Total Direct Expense total for Region (c)]
RETURN
SUMX (
VALUES ( Sheet1[Region] ),
IF (
Sheet1[Region] = "Americas",
CALCULATE (
SUM ( Sheet1[Total Expense (a)] ) - TotalExpense
),
CALCULATE (
SUM ( Sheet1[Total Expense (a)] )
)
)
)
Now the final result is
A rather complex article about ALLSELECTED explaining what is the shadow filter and why calling ALLSELECTED after a context transition in an iteration doesn't work as expcected can be found here https://www.sqlbi.com/articles/the-definitive-guide-to-allselected/
I am currently trying to make a running total for a cumulative plot of some temprature data in Power BI Desktop, but cannot get it to work.
I can see from similar posts on forums that im not the only one. My problem is that I have temperature data from a large table (20-30 degrees) and then made a measure that count the instances of each specific temperature and returns the percentage of the total instances. I want to make a running total which enables me to plot the cumulative distribution.
I have tried ranking the tempertures, and ranking by dates does not make sense. I feel like it is a pretty simple problem but i have not spend 3 days without luck.
I have added some screenshots of my data and progress so far and the code i use to calculate the percentage of the cumulative total, which is the one i want made into a running total.
Hope some of you can help me with some guidance or examples of how to tackle this issue.
Sincerly Lasse
Code
Canvas so far
Data to sum
Fault when ranking
Example of a ranking
Here you can find a good example of running Total
https://www.daxpatterns.com/cumulative-total-excel-2013/
Cumulative Quantity :=
CALCULATE (
SUM ( Transactions[Quantity] ),
FILTER (
ALL ( 'Date'[Date] ),
'Date'[Date] <= MAX ( 'Date'[Date] )
)
)
You can also use this pattern to calculate cumulative if you don't have Date column:
[CumulatedSales] =
CALCULATE (
SUM ( Products[ProductSales] ),
ALL ( Products ),
Products[ProductSales] >= EARLIER ( Products[ProductSales] )
)
I would like to calculate total by category. The category is in the dimension table.
Here is sample file:
DAX ALLEXCEPT total by category.pbix
I have the following model:
These are my expected results. Total by Color:
I thought I could achieve expected results by the following measure:
ALLEXCEPT_color =
CALCULATE (
[Sales],
ALLEXCEPT (
FactTable, -- surprisingly 'dim1' table in that place gives wrong results
dim1[Color]
)
)
Or alternatively using method suggested by Alberto Ferrari https://www.sqlbi.com/articles/using-allexcept-versus-all-and-values/:
ALL_VALUES_color =
CALCULATE (
[Sales],
ALL (FactTable), -- again, 'dim1' produces wrong results, has to be FactTable
VALUES ( dim1[Color] )
)
Both these measures work and return proper results. However they multiply displayed results making Cartesian product of all the dimensions. Why? How to prevent it?
I achieve expected results with measure:
Expected_Results_Color =
IF (
ISBLANK ( [Sales] ),
BLANK (),
[ALLEXCEPT_color]
)
Probably I am missing something about ALLEXCEPT function so I do not get what I want for the first shot. What is the logic behind using ALLEXCEPT function with multiple tables, especially with far off dimensions, away from the center of star schema.
What pattern to use? Here I found promising solution which looks like this:
ByCategories =
CALCULATE (
SUM ( FactTable[Sales] ),
ALLEXCEPT (
dim1,
dim1[Color]
),
ALLEXCEPT (
dim2,
dim2[Size]
),
ALLEXCEPT (
dim3,
dim3[Scent]
)
)
But as I tested it before it does not work. It does not aggregate [Sales] by dimensions but produces [Sales] as they are.
So I found out that this is the correct direction:
ByCategories =
CALCULATE (
SUM ( FactTable[Sales] ),
ALLEXCEPT (
FactTable, -- here be difference
dim1[Color],
dim2[Size],
dim3[Scent]
)
)
I speculate there might be also another way.
Measure =
var MyTableVariable =
ADDCOLUMNS (
VALUES ( dim1[color] ),
"GroupedSales", [Sales]
)
RETURN
...
If only we could retrieve single scalar value of GroupedSales from MyTableVariable and match it with appropriate color in table visual.
I would be very grateful for any further insights in calculating total for category.
This is expected behaviour.
Power BI tables will include every row for which any measure in the table does not evaluate to BLANK().
ALLEXCEPT stops the values in the id and size columns from affecting the filter context when [Sales] is computed, and so every possible value for these two columns will give the same (non-blank) result (this causes the cartesian product that you see).
For example, on the (a, black, big) row, the filter context for the measures contains:
FactTable[id] = {"a"}
dim1[color] = {"black"}
dim2[size] = {"big"}
Then CALCULATE([Sales], ALLEXCEPT(...)) removes the FactTable[id] and dim2[size] from the filter context when evaluating [Sales]; so the new filter context is just:
dim1[color] = {"black"}
[Sales] in this filter context is not BLANK(), so the row is included in the result.
The proper way to fix this is to wrap the result in an IF, as you do in your Expected_Results_Color measure, or to add a filter on [Sales] not Blank to the table in Power BI.
How to create DAX measure returning different value for total in table visual? I would like it for conditional formatting for whatever dimension split in table visuals. But since conditional formatting does not work for totals I do not want to display it for that line.
I need something like:
IF(condition_identifying_total_line, "Alternative result", [TrafficLightIcon])
Edit. This does exactly what I want but I hope for more elegant approach or any other suggestions:
IsTotal =
COUNTROWS(FactTable) =
CALCULATE (
COUNTROWS ( FactTable ),
ALLSELECTED ( FactTable)
)
This measure works for whatever dimension split of Sales figures in table visual.
There are a variety of options depending on exactly what you want to do. I suggest taking a look a the following functions for ideas:
ISFILTERED
ISCROSSFILTERED
HASONEFILTER
HASONEVALUE
FILTERS
SELECTEDVALUE
For example, if Sales broken out by a column A, here are a couple possible approaches:
Sales = IF( HASONEVALUE( T[A] ), SUM ( T[Sales] ), <Alternative Result> )
Sales = IF( ISFILTERED ( T[A] ), <Alternative Result>, SUM ( T[Sales] ) )
You can find full documentation for how to handle granularities from the SQLBI website here: https://www.daxpatterns.com/handling-different-granularities/
Hope this helps!
William
I have ended up using INSCOPE function:
IsTotal = NOT(
ISINSCOPE(products[dimension1])
|| ISINSCOPE(products[dimension2])
|| ISINSCOPE(stores[dimension1])
|| ISINSCOPE(stores[dimension2])
)
Unfortunately it requires hard coding all dimensions by which we want to slice or group visuals.