I have a slicer, called COUNTRY and applied to table MY_TABLE. When I calculate a measure, everything works as expected:
-- calculates distinct count only for COUNTRY = x
Some Measure = DISTINCTCOUNT('MY_TABLE'[SOME_COLUMN])
The problem is SUMMARIZE ignores slicer selection:
-- calculates distinct count accross all countries: x, y, z, etc.
Calculated Table =
RETURN SUMMARIZE(
'SOME_TABLE',
[CATEGORY],
"COUNT", DISTINCTCOUNT('SOME_TABLE'[SOME_COLUMN])
)
How to make SUMMARIZE take into account slicers?
Only Measures are "responsive", calculated tables and columns get calculated and created once, when the data are loaded.
Note that if a calculated table is used inside a measure it will behave correctly, but as you may know, a measure must return a scalar value and not a table. (ie you can use summarize inside a measure, you can then filter the obtained table and return the sum of one column)
Of course, you can filter calculated table with a slicer. If you can, go for SUMMARIZECOLUMNS because this function is better optimized then SUMMARIZE, and has arguments for filtering.
Filtering SUMMARIZECOLUMNS
If you want to stick to SUMMARIZE, you can filter your table by wrapping it with CALCULATETABLE.
Calculated Table =
CALCULATETABLE (
SUMMARIZE (
'SOME_TABLE',
[CATEGORY],
"COUNT", DISTINCTCOUNT ( 'SOME_TABLE'[SOME_COLUMN] )
),
Dim[Color]
= SELECTEDVALUE ( Slicer[SlicerValues] )
)
Should FILTER be used inside or outside of SUMMARIZE?
Related
This works:
EVALUATE
ADDCOLUMNS(
FILTER (Sales, [StoreKey] = 155 ) ,
"Margin", (Sales[SalesAmount] - Sales[TotalCost])
)
However, if I try to define a function, I get an error:
DEFINE VAR Margin = Sales[SalesAmount] - Sales[TotalCost]
EVALUATE
ADDCOLUMNS(
FILTER (Sales, [StoreKey] = 155) ,
"Margin", Margin
)
Query (1, 21) A single value for column 'SalesAmount' in table 'Sales'
cannot be determined. This can happen when a measure formula refers to
a column that contains many values without specifying an aggregation
such as min, max, count, or sum to get a single result.
What is this error and how to fix it?
There are 2 problems with the second code:
It's missing Row Context
VAR is not a function, it's a variable. Functions in DAX are Measures
What is "Row Context"? In short, in Power BI data is stored in a database. When you are referring to a column in the database, you must either: aggregate the data in it (i.e., sum it), or provide a specific row ("row context").
In your first code, function ADDCOLUMNS is an iterator. It means that it loops a table row by row, and for each record does a calculation. Since during each iteration it "knows" which row it's on, you can refer to the table fields without problems.
In the second code, this line:
Margin = Sales[SalesAmount] - Sales[TotalCost]
has no row context - it does not know which record to use for the calculation, and hence the error. You must either aggregate the data first, or put this calculation inside an iterator.
In this particular case, the simplest solution is to use aggregation:
DEFINE
MEASURE 'Sales'Margin = SUM ( Sales[SalesAmount] ) - SUM ( Sales[TotalCost] )
EVALUATE
ADDCOLUMNS (
CALCULATETABLE ( Sales, Sales[StoreKey] = 155 ),
"Margin", [Margin]
)
Here, we first aggregate amounts and costs and calculate margin. Then, inside of ADDCOLUMNS we iterate table Sales filtered for a specific store, and for each row we call the measure defined above.
If you need to use an iterator instead of aggregation, you can do something like this:
DEFINE
MEASURE 'Sales'Margin = SUMX(Sales, Sales[SalesAmount] - Sales[TotalCost] )
EVALUATE
ADDCOLUMNS (
CALCULATETABLE ( Sales, Sales[StoreKey] = 155 ),
"Margin", [Margin]
)
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
I have a measure that retrieves the latest bundle string from a column called Message.
The measure works by getting the first single row from SessionEvents and using MAXX to retrieve the Message from that row.
lastBundle =
VAR SINGLE_ROW = TOPN(1,, FILTER(SessionEvents, SessionEvents[StatusId]=4),
SessionEvents[DateTime],DESC)
return MAXX(SINGLE_ROW, [Message])
I want to use this measure in a calculated column but MAXX is not allowed as a part of a calculated column.
How should i change this calculation to work in a calculated column.
You can use SELECTCOLUMNS instead of MAXX as explained more fully in this related Q&A:
Return top value ordered by another column
lastBundle =
SELECTCOLUMNS (
TOPN (
1,
FILTER ( SessionEvents, SessionEvents[StatusId] = 4 ),
SessionEvents[DateTime], DESC
),
"Message", SessionEvents[Message]
)
But I don't see any reason why MAXX shouldn't work too, except your TOPN function has an extra comma.
Edit: I don't think you can do this at all if you are using a DirectQuery. From Microsoft's documentation:
Limitations in calculated columns: Calculated columns are limited to being intra-row, as in, they can only refer to values of other columns of the same table, without the use of any aggregate functions. [...] Functions that are not supported will not be listed in autocomplete when authoring the DAX for a calculated column, and would result in an error if used.
I having trouble calculating the cumulative sum of a column on PowerBI.
I have a big offer table and I want to run a pareto analysis on it. Following many tutorials, I created a SUMMARIZED table by offer and a sum of their sales. So the table definition is:
summary = SUMMARIZE(big_table; big_table[offer]; "offer sales"; sum(big_table[sales]))
Many of the forums and stackoverflow answers I found have direct me to the following formula for cumulative sum on column:
cum_sales =
CALCULATE(
sum([offer_sales]);
FILTER(
ALLSELECTED(summary);
summary[offer_sales] <= max( summary[offer_sales])
)
)
However the resulting table is not correct:
What I need is simply to have the offers ordered by sales descending and then add the current row's sales amount to the previous row's sales,
So I excepted numbers closer to:
1st row: 1.5M
2nd row: 2.1M
3rd row: 2.6M and so on
But (maybe) because of my data structure and (certainly) lack of knowledge on how PowerBI works, I'm not getting the right results...
Total Amount = SUM ( 'Fact'[Amount] )
Offer Visual Cumulative =
VAR OfferSum =
ADDCOLUMNS (
ALLSELECTED ( 'Offer'[Offer] ),
"amt", [Total Amount]
)
VAR CurrentOfferAmount = [Total Amount]
VAR OffersLessThanCurrent =
FILTER (
OfferSum,
[amt] <= CurrentOfferAmount
)
RETURN
SUMX (
OffersLessThanCurrent,
[amt]
)
There's no need to pre-aggregate to a summary table. We can handle that as in the measure above.
This assumes a single fact table named 'Fact', and a table of distinct offers, 'Offer'.
Depending on what you're doing in terms of other filters on 'Offer', you may need to instead do as below:
Offer Visual Cumulative =
VAR OfferSum =
ADDCOLUMNS (
ALLSELECTED ( 'Offer'[Offer] ),
"amt", CALCULATE ( [Total Amount], ALLEXCEPT ( 'Offer', 'Offer'[Offer] ) )
)
...
The rest of the measure would be the same.
The measure is fairly self-documenting in its VARs. The first VAR, OfferSum is a table with columns ('Offer'[Offer], [amt]). This will include all offers displayed in the current visual. CurrentOfferAmount is the amount for the offer on the current row/axis label of the visual. OffersLessThanCurrent takes OfferSum and filters it. Finally, we iterate OffersLessThanCurrent and add up the amounts.
Here's a sample:
I built a diagram that displays the relative frequencies of my clusters (on the values in the column) and the cumulated frequencies (on the values on the line).
My chart has this aspect:
I would like to add a new column to the right that is equal to the sum of all the values of the previous columns.
The relative frequencies are created using the code below:
"Frequencies UL" :=
CALCULATE (
DISTINCTCOUNT ( 'table1'[Column1] );
USERELATIONSHIP ( 'Order Cluster'[Cluster Name]; table1[tag Cluster] );
SUMMARIZE ( table1; table1[tag Cluster] )
)
I would really appreciate some help!
Thanks
Simply it was necessary to do this:
"Frequencies UL" := IF(SELECTEDVALUE('Order Cluster'[Is Total]);
CALCULATE(DISTINCTCOUNT ('table1'[Column1]); ALL('Order Cluster')); DISTINCTCOUNT('table1'[Column1]))
And this is the result I got!
I'd suggest creating a new table to use for your x-axis.
If your 'Order Cluster' table looks like this:
ClusterName Order
ClusterA 1
ClusterB 2
... ...
ClusterZ 26
You want to add a Total row to the end so try something along these lines:
NewTable = UNION('Order Cluster', {("Total", MAX('Order Cluster'[Order]) + 1)})
Use NewTable[ClusterName] for your chart's x-axis and tweak your cumulative measure to reference NewTable[Order] in the FILTER inequality.
You'll also need to adjust your frequency measure to handle the case when you have the Total cluster (use an IF or SWITCH) and make sure you're evaluating within the correct filter context. Something like this logic:
IF( MAX( NewTable[ClusterName] ) = "Total",
CALCULATE( [Frequency Calc], ALLSELECTED( table1 ) ),
CALCULATE( [Frequency Calc],
FILTER(
ALLSELECTED( table1 ),
table1[tag Cluster] = MAX( NewTable[Order] )
)
)
)
P.S. You might be better off adding the total row to your 'Order Cluster' table in the query editor instead of having another table floating around. In any case, the logic is similar; add a total row to the column you're using for your axis and adjust your measures to handle that category how you want.
A waterfall chart might be another option to consider (and doesn't need nearly as much work), though I don't know that you can include the percent info except in the tooltip.