DAX/PowerBI Rank taking a variable/parameter into account - dax

I'm working on a ranking/scoring system and I'm missing the PERCENTRANK.INC function in powerBI. Instead I have worked out below formula which is the closest I can get.
Score =
DIVIDE (
RANKX (
FILTER ( 'Table', NOT ( ISBLANK ( [Sold amounts] ) ) ),
[Sold amounts],
,
ASC
) - 1,
COUNTROWS ( FILTER ( 'Table', NOT ( ISBLANK ( [Sold amounts] ) ) ) ) - 1
)
I really want to have the formula to take the type of "Fruit" into account in my scoring/ranking.
In short each fruit should be scored separately, with a range per fruit sold.
Could this somehow be done with a variable (VAR)?
Example of data:

This should work.
Score =
VAR fruit = 'Table'[Fruit]
VAR filteredTable = FILTER ( 'Table', NOT ( ISBLANK ( [Sold amount] ) ) && 'Table'[Fruit] = fruit)
RETURN
DIVIDE (
RANKX (
filteredTable,
[Sold amount],
,
ASC
) - 1,
COUNTROWS ( filteredTable ) - 1
)

Related

ALL context removal does not apply

I have defined the following table :
The following measure does not work as expected :
VAR lt_MAX_DATE =
FILTER(
ALL( dim_CALENDAR[DATE] ) ,
dim_CALENDAR[DATE] = MAX( dim_CALENDAR[DATE] )
)
VAR lv_MAX_YEAR_DAY =
CALCULATE(
VALUES( dim_CALENDAR[YEAR_DAY] ) ,
ALL( dim_CALENDAR ) ,
lt_MAX_DATE
)
RETURN
lv_MAX_YEAR_DAY
as I get :
In my mind, I should get 10 for both rows of the Max Date ALL column, but this is not the case.
My question is : why does a dim_CALENDAR[YEAR] context apply even though I have used the ALL() function?
Thank you for your help.
If you want the DAX measure to return the max Year_day of maxYear by ignoring no matter what year is currently visible in the filter context, you can achieve it in many ways. Two of them are as below.
Measure1 =
VAR mxYr =
CALCULATE ( MAX ( dim_Calendar[Year] ), ALL ( dim_Calendar[Year] ) )
RETURN
CALCULATE (
MAX ( dim_Calendar[Year_day] ),
dim_Calendar[Year]=mxYr
)
Measure2 =
VAR mxYr =
CALCULATE ( MAX ( dim_Calendar[Year] ), ALL ( dim_Calendar[Year] ) )
RETURN
CALCULATE (
MAX ( dim_Calendar[Year_day] ),
TREATAS ( { mxYr }, dim_Calendar[Year] )
)
This expression
VAR lt_MAX_DATE =
FILTER(
ALL( dim_CALENDAR[DATE] ) ,
dim_CALENDAR[DATE] = MAX( dim_CALENDAR[DATE] )
)
is the same as
VAR YEARinMatrixRow = SELECTEDVALUE[dim_CALENDAR[YEAR]]
VAR lt_MAX_DATE =
CALCULATETABLE (
FILTER(
ALL( dim_CALENDAR[DATE] ) ,
dim_CALENDAR[DATE] = MAX( dim_CALENDAR[DATE] )
)
,dim_CALENDAR[YEAR] = YEARinMatrixRow
)
So, the result of the expression is the last date of the selected (in Row) year. You get a Row filtering.
The second expression filters the table by
ALL( dim_CALENDAR )
,lt_MAX_DATE
According to DAX priorities, first works ALL(dim_CALENDAR) , then you apply filter - lt_MAX_DATE
So, you get the dim_CALENDAR table, simply filtered by the last day of the year in a matrix row where you get a single value with the VALUES( dim_CALENDAR[YEAR_DAY] ).
You overite ALL( dim_CALENDAR ) by the - lt_MAX_DATE
Normaly, you will get an error with lv_MAX_YEAR_DAY syntax. Calculate returns scalar value, while VALUES() function returns a table even with 1 cell.
As #Mik says, you are restricting the context with
dim_CALENDAR[DATE] = MAX( dim_CALENDAR[DATE] )

how to compute the growth rate in Power Bi using Dax?

I want to have a column in power bi showing the growth rate of sales. I have a table like
year
count
1395
123
1396
232
1397
23
1398
908
1399
678
1400
34
the growth rate is (this year - previous year)/previous year
could you please guide me how I can do this?
When I use the growth the data is like below
You can add a calculated column like this:
growth =
VAR _currentcount = 'Table'[count]
VAR _currentyear = 'Table'[year]
VAR _previouscount =
CALCULATE (
SELECTEDVALUE ( 'Table'[count] ) ,
ALL ( 'Table' ) ,
'Table'[year] = _currentyear - 1
)
RETURN
IF (
NOT ISBLANK ( _previouscount ) ,
DIVIDE ( _currentcount , _previouscount ) - 1
)
or a measure like this, to be used with your year dimension:
growth_measure =
VAR _currentcount = SELECTEDVALUE ( 'Table'[count] )
VAR _currentyear = SELECTEDVALUE ( 'Table'[year] )
VAR _previouscount =
CALCULATE (
SELECTEDVALUE ( 'Table'[count] ) ,
ALL ( 'Table' ) ,
'Table'[year] = _currentyear - 1
)
RETURN
IF (
NOT ISBLANK ( _previouscount ) ,
DIVIDE ( _currentcount , _previouscount ) - 1
)
Giving this result:
All depending on your needs.

How do you repeat rows in a table multiple time

I created a table a DAX Studio and want to repeat all the rows (with all the columns) in a new table multiple times; to my choosing.
//create temp table of Historic Facilities for all annual groups 1 to 3
TABLE HistFac =
ADDCOLUMNS ( FacSchHist,
"Rank", RANKX ( FacSchHist, [WtAvg] ),
"Annual Group", (RANKX ( FacSchHist, [WtAvg] ) - FLOOR((RANKX ( FacSchHist, [WtAvg] ) - 1) /3 * 3,3)))
EVALUATE
NonHistFac
ORDER BY [Annual Group],
[WtAvg] DESC
I want the maintain the original order in the repeated list. There are obviously many ways to construct a table (see code above); however, how does one repeat the list of rows?
Thanks you for any suggestions.
Try to remove the filters that are affecting the measure inside RANKX because of the context transition coming from the table provide in the first argument of GENERATE
DEFINE
TABLE HistFac =
GENERATE (
{ 1, 2, 3 },
ADDCOLUMNS (
ADDCOLUMNS (
FacSchHist,
"#Rank",
RANKX (
FacSchHist,
CALCULATE ( [WtAvg], REMOVEFILTERS ( TableSupliedInTheFirstArgument ) )
)
),
"Annual Group",
[#Rank]
- FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
)
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
Or simply use variables to compute in a different filter context.
DEFINE
TABLE HistFac =
VAR RankedTable =
ADDCOLUMNS ( FacSchHist, "#Rank", RANKX ( FacSchHist, [WtAvg] ) )
VAR SomeCalculationOnRankedTable =
ADDCOLUMNS (
RankedTable,
"Annual Group",
[#Rank]
- FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
RETURN
GENERATE ( { 1, 2, 3 }, SomeCalculationOnRankedTable )
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
You can use GENERATE for repeating the rows:
DEFINE
TABLE HistFac =
GENERATE (
{ 1, 2, 3 },
ADDCOLUMNS (
FacSchHist,
"Rank", RANKX ( FacSchHist, [WtAvg] ),
"Annual Group",
(
RANKX ( FacSchHist, [WtAvg] )
- FLOOR ( ( RANKX ( FacSchHist, [WtAvg] ) - 1 ) / 3 * 3, 3 )
)
)
)
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
A better way to write this code will be to use nested ADDCOLUMNS:
DEFINE
TABLE HistFac =
GENERATE (
{ 1, 2, 3 },
ADDCOLUMNS (
ADDCOLUMNS ( FacSchHist, "#Rank", RANKX ( FacSchHist, [WtAvg] ) ),
"Annual Group",
[#Rank]
- FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
)
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
AntrikshSharma - I will give those a try now , appreciate your guidance.
Okay, the code worked fine; but uncovered a problem. After the initial ranking of the list, and before the replication - I do not want to continue ranking.
In other words, I want the initial ranked-list to be reproduced 3x without any further ranking; just have each duplicated occurrence appear after the initial list in the exact order.
If the initial list was 12345, then 12345,12345,12345 - thank you for the more efficient code as well.
AntrikshSharma, your comment and code, "Or simply use variables to compute in a different filter context" is genius. The code performed as expected. The problem I'm experiencing is with the UNION of the two tables "NonHistFac" and "HistFac". I will provide an image to explain then the most current code.
15yr cycle of Hist & NonHist Facilities
The image shows the goal. combine the NonHistFac (all surveyed every 5yrs) with the HistFac (all surveyed every 3yrs). The original ranking must be maintained (this is currently met.)
Here is the problem. The numbers within the image are the Values as produced by the GENERATE function. When the tables are combined and the NonHistFac are mixed with the HistFac, they are not evenly distributed throughout the 1 to 5 Values.
What appears in Values 4 and 5 is obviously the remaining HistFac. I need to have the entire combination distributed from 1 to 5; or as shown, over the 15 year cycle.
Thank you.
// produce non-historic table with additional columns and replicate all rows 3x
TABLE NonHistFac =
VAR NonHistRankedTable =
ADDCOLUMNS ( FacSchNonHist, "#Rank", RANKX ( FacSchNonHist, [WtAvg] ) )
VAR NonHistAnnualizedRankedTable =
ADDCOLUMNS (
NonHistRankedTable,
"Annual Group",
[#Rank] - FLOOR ( ( [#Rank] - 1 ) / 5 * 5, 5 )
)
RETURN
GENERATE ( { 1, 2, 3 }, NonHistAnnualizedRankedTable )
// from the FLOOR & GENERATE functions, 5 x 3 = 15 (this is a 15 year cycle)
//produce historic facility table with additional columns and replicate all rows 5x
TABLE HistFac =
VAR HistRankedTable =
ADDCOLUMNS ( FacSchHist, "#Rank", RANKX ( FacSchHist, [WtAvg] ) )
VAR HistAnnualizedRankedTable =
ADDCOLUMNS (
HistRankedTable,
"Annual Group",
[#Rank] - FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
RETURN
GENERATE ( { 1, 2, 3, 4, 5 }, HistAnnualizedRankedTable )
// from the FLOOR & GENERATE functions, 3 x 5 = 15 (this is a 15 year cycle)
// combine the tables NonHistFac & HistFac to create one-table representing a 15 yr cycle
VAR FacSchUnion =
UNION(
NonHistFac,
HistFac
)
VAR FacSch15yr =
DISTINCT(FacSchUnion)
EVALUATE
FacSch15yr
ORDER BY [Value],
[Annual Group],
[WtAvg] DESC

How to distinctly count customer IDs that visited a store in a given quarter only if the same customer ID visited in the previous quarter

I have a table
+-----------+----------+--------+-------+---------+
|Customer ID|Visit Date|Category|Product|Served by|
+-----------+----------+--------+-------+---------+
|1001 |03/17/2019|A |P11 |Jone Doe |
|1003 |03/17/2019|D |P12 |Jone Doe |
|1006 |03/15/2019|C |P13 |Jone Doe |
|1009 |03/10/2019|G |P14 |Jone Doe |
|1011 |12/12/2018|H |P15 |Foo Bar |
|1003 |11/11/2018|D |P16 |Foo Bar |
|1006 |09/10/2018|C |P17 |Foo Bar |
|1009 |10/10/2018|G |P18 |Foo Bar |
+-----------+----------+--------+-------+---------+
there are 4 customers but only 2 (1003 and 1009) visited in the previous quarter.
I used DATESINPERIOD but it counts all distinctly between the preceding quarters (I have a designated date table).
1st approach
customers_count =
CALCULATE (
DISTINCTCOUNT[Customer ID],
DATESINPERIOD (
'Calendar'[Date],
ENDOFQUARTER ( 'Calendar'[Date] ),
-2,
QUARTER
)
)
2nd approach
customers_count 2Q =
VAR customers_count_1 =
DISTINCT ( FILTER ( VALUES ( Orders[Customer ID] ) ) )
VAR customers_count_2 =
CALCULATETABLE (
DISTINCT ( FILTER ( VALUES ( Orders[Customer ID] ) ) ),
DATEADD ( 'Calendar'[Date], -1, QUARTER )
)
RETURN
COUNTROWS ( INTERSECT ( customers_count_1, customers_count_2 ) )
The expected count is 2 for the last quarter.
Your second approach looks reasonable. Try it without DISTINCT and FILTER.
customers_count 2Q =
VAR customers_count_1 =
VALUES ( Orders[Customer ID] )
VAR customers_count_2 =
CALCULATETABLE (
VALUES ( Orders[Customer ID] ),
DATEADD ( 'Calendar'[Date], -1, QUARTER )
)
RETURN
COUNTROWS ( INTERSECT ( customers_count_1, customers_count_2 ) )
The VALUES function returns a list of distinct values of its column argument that are within its filter context.

How to pass a filtered table to RankX

I would like RankX to rank products for Var2 and only consider/see products who have a value for Var1 (so only A and B and not C).
Here is an example datamodel including the resulting pivottable
And here are the measures I use:
SUM Value = SUM ( Data[Value] )
Var1 Check = CALCULATE ( COUNTROWS ( Data ), Variable[Variable] = "Var1" )
RankX = RANKX ( ALL ( 'Product' ), [SUM Value] )
RankX Filter = IF ( ISBLANK ( [Var1 Check] ), BLANK (), [RankX] )
The idea is that my filtered RankX function (RankX Filter) shows 2 instead of 3 for Product B as only A and B should be considered.
Using DAX Studio I managed to filter my product table accordingly but I don't know whether this the right approach nor how to pass that filtered table to a RankX function.
FILTER (
ADDCOLUMNS (
'Product',
"Var1Check", CALCULATE ( COUNTROWS ( Data ), Variable[Variable] = "Var1" )
),
[Var1Check] = 1
)
You should just be able to put the filtered table as the first argument in your RANKX function. Something along these lines:
RANKX ( FILTER ( 'Product', Variable[Variable] = "Var1" ), [SUM Value] )

Resources