ASC parameter when using TOPN function in Power BI - powerbi

I've got this data:
Then have this measure:
amount = SUM( play[amount] )
Then I've tried to use the ASC/DESC arguments of the TOPN function in these two measures:
Top 2 customer per category ASC =
VAR rnk = VALUES( play[customer] )
RETURN
CALCULATE(
[amount],
TOPN(
2,
ALL( play[customer] ),
[amount],
ASC
),
RNK
)
Top 2 customer per category DESC =
VAR rnk = VALUES( play[customer] )
RETURN
CALCULATE(
[amount],
TOPN(
2,
ALL( play[customer] ),
[amount],
DESC
),
RNK
)
Now if I use these two measures it looks like the following:
What is going on?
Why is the measure Top 2 customer per category ASC showing nothing?
How do I amend that measure so that it shows values for the bottom two values of each category?

The problem here is that the second argument of TOPN should be a table, not an unfiltered column.
Regardless of what the category is, ALL(play[customer]) returns the table:
customer
--------
xx
yy
zz
jj
qq
ff
The measure [amount] is still evaluated within the category filter context though so for category = "a" you get
customer [amount]
------------------
xx 10
yy 12
zz 13
jj
qq
ff
and for category = "b" you get
customer [amount]
------------------
xx
yy
zz
jj 15
qq 16
ff 9
These blanks are considered smaller than any number so they are what gets selected when you sort ASC.
Try this slightly modified measure instead:
Top 2 customer per category ASC =
VAR rnk = VALUES ( play[customer] )
RETURN
CALCULATE (
[amount],
TOPN ( 2, CALCULATETABLE ( play, ALL ( play[customer] ) ), [amount], ASC ),
RNK
)
Using CALCULATETABLE, the category filter context gets preserved.
P.S. To generate the tables above you can write a new calculated table like this:
Top2Table =
CALCULATETABLE (
ADDCOLUMNS ( ALL ( play[customer] ), "amount", [amount] ),
play[category] = "a" <or "b">
)

Related

Is there any DAX Measure that Count rows that have an ID matching another row, but a different value in the column

I have a table with ID and with different statuses but some are not having both. I need create measure that will give the count for all the ID's that are having different statues.
I have tried below Dax functions but not giving the expected results.
Link-EC-Count =
VAR count_Donor =
CALCULATE (
DISTINCTCOUNT ( MagentaBuilt_Linked[Microwave IQ Link ID] ),
FILTER (
ALLEXCEPT ( MagentaBuilt_Linked, MagentaBuilt_Linked[Microwave IQ Link ID] ),
MagentaBuilt_Linked[Site_Nature] = "Donor"
),
FILTER (
MagentaBuilt_Linked,
MagentaBuilt_Linked[Primary AAV Vendor] = "T-Mobile"
)
)
VAR count_Recepient =
CALCULATE (
DISTINCTCOUNT ( MagentaBuilt_Linked[Microwave IQ Link ID] ),
FILTER (
ALLEXCEPT ( MagentaBuilt_Linked, MagentaBuilt_Linked[Microwave IQ Link ID] ),
MagentaBuilt_Linked[Site_Nature] = "Recipient"
),
FILTER (
MagentaBuilt_Linked,
MagentaBuilt_Linked[Primary AAV Vendor] = "T-Mobile"
)
)
RETURN
IF ( count_Donor > 0 && count_Recepient > 0, 1, 0 )
Here is the sample data looks like
Anybody have any ideas?
Here's a calculated column formula for "Eligible Row?" that works:
Eligible Row? =
IF(
CALCULATE(
COUNTROWS('Table'),
FILTER('Table',
'Table'[Affiliate ID]=EARLIER('Table'[Affiliate ID]) &&
'Table'[Achievement Type] <> EARLIER('Table'[Achievement Type])))>0,
"Yes","No")
The idea is to filter the table for rows when the Affiliate ID matches, then filter for rows where the Achievement is different, then count the rows.
Here are formulas for my two intermediate calculated columns:
Count ID =
CALCULATE(
COUNTROWS('Table'),
FILTER('Table',
'Table'[Affiliate ID]=EARLIER('Table'[Affiliate ID])))
Count Other Achievements =
CALCULATE(
COUNTROWS('Table'),
FILTER('Table',
'Table'[Affiliate ID]=EARLIER('Table'[Affiliate ID]) &&
'Table'[Achievement Type] <> EARLIER('Table'[Achievement Type])))
I think This is what you need. Try this code as measure:
Count ID =
VAR TblSummary = ADDCOLUMNS(
SUMMARIZE('Sheet 1','Sheet 1'[Affiliate Id],'Sheet 1'[Achievement Type]),
"UniqueCount",CALCULATE(COUNT('Sheet 1'[Affiliate Id]),ALLEXCEPT('Sheet 1','Sheet 1'[Affiliate Id]))
)
RETURN
SUMX(TblSummary,IF([UniqueCount]>1,[UniqueCount]))
If we test it on a visual:

Issue with TOPN and SUMMARIZE in Dax

I'm trying to find the top 5 items sales based on the turnover but I keep receiving this error : The expression refers to multiple columns. Multiple columns cannot be converted to a scalar value.
Top_Five_Items_Turnover =
VAR X =
CALCULATE(
TOPN(
5,
SUMMARIZE(
Sales,
Sales[item],
"Top_Five",
Sales[item]
),
[Turnover], DESC
),
Sales[item]
)
RETURN
X
Hi you cannot return a entire table using a measure. instead return values.
Top 5 =
VAR totalSales =
SUM ( Sales[item] )
RETURN
CALCULATE (
totalSales,
FILTER (
VALUES ( Sales[item] ),
IF (
RANKX ( ALL ( Sales[item]), [Turnover], desc) <= 5,
[Total Sales],
BLANK ()
)
)
)

How to calculate rank within Sales ranges

How to calculate rank within Category defined on sales level. Say, that we want to label products with Sales above some threshold with Category "high", and below that threshold with Category "low".
Here is a sample data.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WcisqzSwpVtJRSiwoyEkF0oZKsTpIwkmJeUAIZJigipfn56QlpRYVVQLZpqhSyRlQcWOweFhqempJYlJOKlgusagovwS7XEF+SWJJPtwJKHL5eZn5eUDaHNUqHI5GdkEsAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [Category = _t, Product = _t, Amount = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Amount", Int64.Type}})
in
#"Changed Type"
My question is a nephew related to its older uncle, who now I want to call in:
Percent Rank within Category =
VAR HasOneValueTrue = HASONEVALUE ( MyTable[Product] )
VAR tbl =
CALCULATETABLE (
VALUES ( MyTable[Product] ),
REMOVEFILTERS ( MyTable[Product] ),
VALUES ( MyTable[Category] )
)
VAR result =
CALCULATE (
DIVIDE (
RANKX (
tbl,
[Sales],
,
ASC
) - 1,
COUNTROWS ( tbl ) - 1
)
)
RETURN
IF (
HasOneValueTrue,
result
)
The difference is that the uncle has Category defined in table column, but now we want to have category calculated on the fly based on sales level. So I tried
replacing the VAR tbl code with the following one with the threshold of 4:
var tbl =
SUMMARIZECOLUMNS (
MyTable[Product],
"CalculatedCategory", IF ( [Sales] > 4, "high", "low" ),
"AggSales", [Sales]
)
Nevertheless, I am not able to refer to such defined variable. I also failed with trial based on creating first a DAX table and then trying to refer to it.
Here are expected results:
References
Here is the family of related questions which members I met on the way while approaching to state this problem.
DAX equivalent of Excel PERCENTRANK.INC per category
DAX RANKX for within Category
DAX REMOVEFILTERS vs ALL
The value parameter in DAX function RANKX
DAX ALLEXCEPT to sum by category of multiple dimension tables
This can be done with a minor modification to my answer here. Copied below:
Percent Rank =
VAR ProductsInCategory =
CALCULATETABLE (
VALUES ( MyTable[Product] ),
ALLSELECTED ( MyTable[Product] )
)
VAR RankProduct = RANKX ( ProductsInCategory, [Sales],, ASC )
RETURN
IF (
HASONEVALUE ( MyTable[Product] ),
DIVIDE ( RankProduct - 1, COUNTROWS ( ProductsInCategory ) - 1 )
)
First, define the calculated category as you suggested.
CalculatedCategory = IF ( [Sales] > 4, "high", "low" )
Then plug that into a filter in the ProductsInCategory variable.
Exp. Results =
VAR CalculatedCategory = [CalculatedCategory] /*Determine current category*/
VAR ProductsInCategory =
CALCULATETABLE (
VALUES ( MyTable[Product] ),
FILTER (
ALLSELECTED ( MyTable[Product] ),
[CalculatedCategory] = CalculatedCategory /*New Condition*/
)
)
VAR RankProduct = RANKX ( ProductsInCategory, [Sales],, ASC )
RETURN
IF (
HASONEVALUE ( MyTable[Product] ),
DIVIDE ( RankProduct - 1, COUNTROWS ( ProductsInCategory ) - 1 )
)
Output:
Edit:
To handle the case where there is only 1 product in a category, you can use MAX to disallow a zero value for the denominator.
Exp. Results =
VAR CalculatedCategory = [CalculatedCategory] /*Determine current category*/
VAR ProductsInCategory =
CALCULATETABLE (
VALUES ( MyTable[Product] ),
FILTER (
ALLSELECTED ( MyTable[Product] ),
[CalculatedCategory] = CalculatedCategory /*New Condition*/
)
)
VAR RankProduct = RANKX ( ProductsInCategory, [Sales],, ASC )
RETURN
IF (
HASONEVALUE ( MyTable[Product] ),
DIVIDE (
RankProduct - 1,
MAX ( COUNTROWS( ProductsInCategory ) - 1, 1 )
)
)
Being very grateful to Alexis Olson, I would like to share a different solution I ended up with. The solution proposed by Alexis works well in my simple example, but it did not work in my complex model. In my complex model the RANKX function does not give the expected results. RANKX returns the same rankings for different sales values.
For the time being this is the solution that works without figuring out what causes RANKX to return ties for different sales values.
First of all, defining Category measure:
CalculatedCategory =
SWITCH (
TRUE (),
NOT ( HASONEVALUE ( MyTable[Product] ) ), "total", -- important to handle totals
[Sales] <= 4, "low",
[Sales] > 4, "high",
"other"
)
It is important to exclude totals from Category. I did it by setting up a different category for totals. Otherwise totals will fall into "high" category bucket. It would distort final results.
I have not used RANKX in calculation of Percent Rank within Category. I used MIXTURE OF COUNTROWS and FILTER.
PercentRank within Category =
VAR category = [CalculatedCategory]
VAR ProductSales = [Sales]
VAR ProductsMatching =
COUNTROWS (
FILTER (
ALLSELECTED ( MyTable[Product] ),
[CalculatedCategory] = category
&& [Sales] >= ProductSales
)
)
var ProductsAll =
COUNTROWS (
FILTER (
ALLSELECTED ( MyTable[Product] ),
[CalculatedCategory] = category
)
)
RETURN
DIVIDE (ProductsMatching-1, MAX( ProductsAll-1, 1 ))
I calculated rows of two tables. First table ProductsMatching has all products that have sales in appropriate category and sales that are higher or equal of the product. ProductsAll returns number of products in category.

DAX time intelligence functions with nested filters

I have a data structure like this
DateRoll Dataset Date Value Customer
Month Online 1/1/2018 10 Cust1
Month Online 2/1/2018 11 Cust1
Month Online 3/1/2018 12 Cust1
Month Online 4/1/2018 22 Cust1
Quarter Online 1/1/2018 33 Cust1
Quarter Online 4/1/2018 22 Cust1
I have to calculate previous quarter value, I tried different ways but it's not working
1 - Not returning any value.
CALCULATE (
SUM ( 'Data_Rollup_KPI_DNR'[Value] ),
DATEADD ( 'Data_Rollup_KPI_DNR'[Date].[Date], -1, QUARTER ),
FILTER ( Data_Rollup_KPI_DNR, Data_Rollup_KPI_DNR[DateRoll] = "Quarter")
)
2--Nested - Returning overall total
CALCULATE (
CALCULATE (
SUM ( 'Data_Rollup_KPI_DNR'[Value] ),
DATEADD ( 'Data_Rollup_KPI_DNR'[Date].[Date], -1, QUARTER )
),
FILTER ( Data_Rollup_KPI_DNR, Data_Rollup_KPI_DNR[DateRoll] = "Quarter" )
)
3--Nested --Returning overall total
CALCULATE (
CALCULATE (
SUM ( 'Data_Rollup_KPI_DNR'[Value] ),
FILTER ( Data_Rollup_KPI_DNR, Data_Rollup_KPI_DNR[DateRoll] = "Quarter" )
),
DATEADD ( 'Data_Rollup_KPI_DNR'[Date].[Date], -1, MONTH )
)
Tried PREVIOUSQUARTER function too, but its not returning any value.
To take advantage of built in DAX time intelligence functions you will need to to have a contiguous set of dates. I would recommend using a date table. The following code can be used to create a date/calendar table in your model:
Celndar =
Var MinDate = MIN(Data_Rollup_KPI_DNR[Date])
Var MaxDate = MAX(Data_Rollup_KPI_DNR[Date])
Var BaseCalendar = CALENDAR(MinDate, MaxDate)
RETURN
GENERATE (
BaseCalendar,
VAR BaseDate = [Date]
VAR YearDate =
YEAR ( BaseDate )
VAR MonthNumber =
MONTH ( BaseDate )
VAR YrMonth =
100 * YEAR ( BaseDate )
+ MONTH ( BaseDate )
VAR Qtr =
CONCATENATE ( "Q", CEILING ( MONTH ( BaseDate ) / 3, 1 ) )
RETURN
ROW (
"Day", BaseDate,
"Year", YearDate,
"Month Number", MonthNumber,
"Month", FORMAT ( BaseDate, "mmmm" ),
"Year Month", FORMAT ( BaseDate, "mmm yy" ),
"YrMonth", YrMonth,
"Qtr", Qtr
)
)
Once this table exists, mark it as a 'date' table and create a relationship with
Data_Rollup_KPI_DNR[Date]
Then, you can write the following measure to obtain the results you are searching for:
PQSum =
CALCULATE (
SUM ( 'Data_Rollup_KPI_DNR'[Value] ),
PREVIOUSQUARTER ( 'Calendar'[Date] )
)
Hope that helps!
*Edited
You can also create a ranking column to index in a measure:
Rank =
RANKX (
FILTER (
'Data_Rollup_KPI_DNR',
'Data_Rollup_KPI_DNR'[DateRoll] = EARLIER ( 'Data_Rollup_KPI_DNR'[DateRoll] )
),
'Data_Rollup_KPI_DNR'[Date].[Date],
,
ASC
)
Then you can reference a previous quarter using something like the following:
PQSum2 =
CALCULATE (
SUM ( 'Data_Rollup_KPI_DNR'[Value] ),
FILTER (
'Data_Rollup_KPI_DNR',
'Data_Rollup_KPI_DNR'[Rank]
= MAX ( 'Data_Rollup_KPI_DNR'[Rank] ) - 1
),
'Data_Rollup_KPI_DNR'[DateRoll] = "Quarter"
)
but this is hard coded and just plain nasty!
Echoing #steliok that a date dimension is the proper way to handle this; there are plenty of date table templates out there, and a date dimension will work with your data model. If you really really can't add to your data structure for some reason, this should work:
BaseValue = SUM ( 'Data_Rollup_KPI_DNR'[Value] )
PriorQuarter =
VAR CurrentDate = MAX ( 'Data_Rollup_KPI_DNR'[Date] )
VAR CurrentYear = YEAR ( CurrentDate )
VAR CurrentMonth = MONTH ( CurrentDate )
VAR FirstMonthOfCurrentQuarter =
SWITCH (
TRUE (),
CurrentMonth IN {1,2,3}, 1,
CurrentMonth IN {4,5,6}, 4,
CurrentMonth IN {7,8,9}, 7,
CurrentMonth IN {10,11,12}, 10
)
// DATE() does the right thing with negative month args
VAR PriorQuarterDate = DATE ( CurrentYear, FirstMonthOfCurrentQuarter - 3, 1 )
RETURN
CALCULATE (
[BaseValue],
ALL ( 'Data_Rollup_KPI_DNR'[DateRoll], 'Data_Rollup_KPI_DNR'[Date] ),
'Data_Rollup_KPI_DNR'[Date] = PriorQuarterDate,
'Data_Rollup_KPI_DNR'[DateRoll] = "Quarter"
)
This relies on DATE being clever, which it is. DATE ( 2019, -2, 1 ) = DATE ( 2018, 10, 1 ).
Ultimately, my question is why can't you just source the un-rolled up data from the same place that the ETL process is sourcing it?
Date functions are working well when you are using # Day level.
Following link would be helpful to resolve your issue,
https://community.powerbi.com/t5/Desktop/Lead-and-Lag-in-DAX/td-p/649162

Pareto (80/20) Segmentation in Power BI

I created 80/20 segmentation in my Power BI data model and I got what I wanted (see the table below).
Now I want to calculate new Name column with the next logic: if Cumulative % <=80% show value from the "Customer Name" column, otherwise show "Other" (the result will be the column Name as in the table below).
I tried with this calculated column but it doesn't work (the result isn't correct, it's always "Other"):
80/20 Name = IF([Cumulative Percen.] <= 0.8, SalesReport[Names], "Other")
Note: "Cumulative Percen." is calculated measure.
How can I do this?
In the next step, I'll use a pie chart to show this segmentation where all customers with small cumulative transactions will be categorized as Other.
The calculated measures that I used:
Customer Rank by Transaction =
IF (
HASONEVALUE ( SalesReport[CustName] ),
RANKX (
ALLSELECTED ( SalesReport[CustName] ),
CALCULATE ( [# of Transactions] ),
,
DESC,
DENSE
)
)
Customer Cumulative Transaction =
VAR CurrentCustimerRank = [Customer Rank by Transaction]
RETURN
SUMX (
FILTER (
ALLSELECTED ( SalesReport[CustName] ),
CALCULATE ( [Customer Rank by Transaction] ) <= CurrentCustimerRank
),
CALCULATE ( DISTINCTCOUNT ( SalesReport[CustID] ) )
)
Customer Cumulative Transaction Percen. =
[Customer Cumulative Transaction]
/ CALCULATE (
DISTINCTCOUNT ( SalesReport[CustID] ),
ALLSELECTED ( SalesReport[CustName] )
)