How can I select the value of the nth row in a column in Powerbi? - powerbi

I am fairly new to PowerBi,
I am trying to select the top 3 values from a table but only use specific column values. My instinct is to create a measure for each row. Here is a sample table of the data.
I've tried this but don't know enough of DAX to know how to go any further. I am able to select the top 1 value, but if I change N to 3 it doesnt work. Even if I can choose the second value instead of just the first one would help. Some sort of row index or number in an array fashion.
row[1][name]
LowestSpenders =
"The lowest spenders for the day are "
&
CALCULATE(
VALUES(Top3Low[Name]),
TOPN(1, Top3Low, Top3Low[Spent], DESC)
)
I have also tried this
LowestSpenders =
"The lowest spenders for the day are "
&
CONCATENATEX(
Top3Lost,
VALUES(Top3Lost[ClientName]),
",",
Top3Lost[LastYear],
DESC
)
I want to select the names of the people based on their positions in the table and include them in a dynamic text measure.
Something like this.
"The lowest spenders for the day are: Bob, John and Mark"

How about something like this? Rank all the names and then pick out whatever ranks you want.
LowestSpenders =
VAR Summary =
SUMMARIZE (
Top3Low,
Top3Low[Name],
"Rank", RANK.EQ ( Top3Low[Spent], Top3Low[Spent], 1 )
)
RETURN
CONCATENATEX (
FILTER ( Summary, [Rank] IN { 1, 2, 3 } ),
[Name],
", "
)
Instead of [Rank] IN { 1, 2, 3 }, you can substitute whatever criterion you want, for example, [Rank] = 2 or [Rank] > 2 && [Rank] < 5.

You're nearly there.
Use TOPN to identify the lowest n spenders, and use CONCATENATEX to iterate over this table and concatenate the names:
LowestSpenders =
CONCATENATEX (
TOPN (
3,
MyTable,
MyTable[Spent],
ASC
),
MyTable[Name],
", "
)

Related

Group by date, Distinct and ignore other filters - Power BI

I have the dataset where the values in the col 'value' are repeated per month and id, e.g. for 1/1/2020 and id 1, the value is 0.5, for 2/1/2020, the value is 2, etc. The dataset has other columns which are to be used as filters for other calculations.
What will be the measure to get:
so that even when I use filters from the table, e.g. filter1, the value remains grouped by date ONLY?
I've tried with sumx and max; sum and value but nothing gives a result and calculation still reacts on other filters.
When i spoke abount ALL i had in mind this kind of solution:
WithoutExternalFilter =
CALCULATE (
VAR __dist =
ADDCOLUMNS (
SUMMARIZE ( Te, Te[Date], Te[ID] ),
"val", CALCULATE ( MAX ( Te[value] ) )
)
RETURN
SUMX ( __dist, [val] ),
ALL ( Te[filter1] )
)
WHEN we put some filter, value for "2020-08-01" is still 1.1:

Equal bins in DAX equivalent of NTILE function

I would like to imitate NTILE function of SQL in DAX. For a given number of bins, I would like a measure which returns the bin number for any value in a column. The bins should contain more or less equal number of observations.
So the parameters are:
number of bins
test value
table column
Here is something similar in Excel:
= MAX( ROUNDUP( PERCENTRANK($A$1:$A$8, A1) *4, 0),1)
In DAX, you can use the PERCENTILE.INC as the base for such a calculation.
Bucket =
VAR N = 4
VAR Percentiles =
ADDCOLUMNS (
GENERATESERIES ( 1, N ),
"Percentile", PERCENTILE.INC ( Table1[Col1], [Value] / N )
)
RETURN
MINX ( FILTER ( Percentiles, Table1[Col1] <= [Percentile] ), [Value] )
For your data, the Percentiles table variable looks like this:
Value Percentile
1 24.8
2 66.5
3 81.8
4 85.0
Then for each row in your original table, you take the minimum value from the calculated table where that Percentile column is less than or equal to the original table column Col1 in that row.
Note that the above is for a calculated column. For a measure, you'd need to specify an aggregation for Table1[Col1] in the last line (e.g. MAX(Table1[Col1])).

TopN, Grouping, Show Others at the bottom POWERBI-DAX

I have the following formula which creates the table in the screenshot below on the left (names of actual tables are different - also it combines 2 separate tables in one) -
Top 11 Jun =
IF (
[Type Rank Jun] <= 11,
[Total Jun],
IF (
HASONEVALUE ( Partners[partner_group] ),
IF (
VALUES ( Partners[partner_group] ) = "Others",
SUMX (
FILTER ( ALL ( Partners[partner_group] ), [Type Rank Jun] > 11 ),
[Total Jun]
)
)
)
)
Now i'm stuck on how to combine the "Null" and "Others" under "Others" and put "Others" at the bottom.i can combine the "Null" & "Others" at each table level, i'm just not sure how.
The DAX solution:
To get the Other and blank (at least that is how I read your null) together, you can create a new column on the table (is easiest).
newProducts = IF(fruits[product] = BLANK(); "Other";fruits[product])
A better solution is to replace your blanks (or NULL) in the Query language:
Go to: Edit Query:
Select your table and the product column and press on the bar the "Replace values"
Do the replace and save and close the editor.
Last step
It is not relevant in which order you have the rows in the table because you can control this in the visual self.
Below example:
As you can see, I filtered other out, this is not needed when you want to count them in your top N.
If you want to show all four, we need to make a new Table:
Tabel =
var Top3 = TOPN(3;FILTER(fruits;fruits[product] <> "Other") ;fruits[July Avail])
var prioTop3 = ADDCOLUMNS(Top3;"Order"; CALCULATE(COUNTROWS(fruits);FILTER(Top3; fruits[July Avail] <= EARLIER(fruits[July Avail]))))
var Other = ADDCOLUMNS(GROUPBY(FILTER(fruits;fruits[product] = "Other");fruits[product];"June Avail"; SUMX(CURRENTGROUP();fruits[June Avail]); "July Avail"; SUMX(CURRENTGROUP();fruits[July Avail]));"Order";0)
return UNION(prioTop3; Other)
Result:

Intersection of Customer product purchase (powerBI)

I need help with producing a count of the intersections between customers and which items they have purchased. For example, if there are 5 products, a customer can purchase any single product or any combination of the 5. Customers can also re-purchase a product at any date - this is where my problem arises as an end user wants to be able to see the intersections for any selected date range.
I have managed to come up with a solution which includes the use of parameters but this is not ideal as the end user does not have access to change any parameters of the report.
I'm open to any solution that does not involve parameters, ideally a slicer with dates would be the best solution
The fields I have on the table are customer_ID, date_ID, and product
Example Data
customer_id date_id product
1 9/11/2018 A
1 10/11/2018 A
1 10/11/2018 B
1 11/11/2018 C
1 11/11/2018 A
2 9/11/2018 C
2 10/11/2018 D
2 11/11/2018 E
2 11/11/2018 A
3 10/11/2018 A
3 10/11/2018 B
3 11/11/2018 A
3 11/11/2018 B
3 11/11/2018 B
4 10/11/2018 A
4 11/11/2018 A
5 9/11/2018 A
5 10/11/2018 B
5 10/11/2018 E
5 10/11/2018 D
5 11/11/2018 C
5 11/11/2018 A
6 9/11/2018 A
6 10/11/2018 A
6 11/11/2018 A
Possible output with different slicer selections
Any help at all would be greatly appreciated
This is pretty tricky since I can't think of a way to use the values of a dynamically calculated table as a field in a visual. (You can create calculated tables, but those aren't responsive to slicers. You can also create dynamically calculated tables inside of a measure, but measures don't return tables, just single values.)
The only way I can think of to do this requires creating a table for every possible product combination. However, if you have N products, then this table has 2N rows and that blows up fast.
Here's a calculated table that will output all the combinations:
Table2 =
VAR N = DISTINCTCOUNT(Table1[product])
VAR Products = SUMMARIZE(Table1,
Table1[product],
"Rank",
RANKX(ALL(Table1),
Table1[product],
MAX(Table1[product]),
ASC,
Dense
)
)
VAR Bits = SELECTCOLUMNS(GENERATESERIES(1, N), "Bit", [Value])
VAR BinaryString =
ADDCOLUMNS(
GENERATESERIES(1, 2^N),
"Binary",
CONCATENATEX(
Bits,
MOD( TRUNC( [Value] / POWER(2, [Bit]-1) ), 2)
,,[Bit]
,DESC
)
)
RETURN
ADDCOLUMNS(
BinaryString,
"Combination",
CONCATENATEX(Products, IF(MID([Binary],[Rank],1) = "1", [product], ""), "")
)
Then add a calculated column to get the column delimited version:
Delimited =
VAR Length = LEN(Table2[Combination])
RETURN
CONCATENATEX(
GENERATESERIES(1,Length),
MID(Table2[Combination], [Value], 1),
","
)
If you put Delimited the Rows section on a matrix visual and the following measure in the Values section:
customers =
VAR Summary = SUMMARIZE(Table1,
Table1[customer_id],
"ProductList",
CONCATENATEX(VALUES(Table1[product]), Table1[product], ","))
RETURN SUMX(Summary, IF([ProductList] = MAX(Table2[Delimited]), 1, 0))
And filter out any 0 customer values, you should get something like this:
So yeah... not a great solution, especially when N gets big, but maybe better than nothing?
Edit:
In order to work for longer product names, let's use a delimiter in the Combination concatenation:
CONCATENATEX(Products, IF(MID([Binary],[Rank],1) = "1", [product], ""), ",")
(Note the "" to "," change at the end.)
And then rewrite the Delimited calculated column to remove excess commas.
Delimited =
VAR RemoveMultipleCommas =
SUBSTITUTE(
SUBSTITUTE(
SUBSTITUTE(
SUBSTITUTE(Table2[Combination], ",,", ","),
",,", ","),
",,", ","),
",,", ",")
VAR LeftComma = (LEFT(Table2[Combination]) = ",")
VAR RightComma = (RIGHT(Table2[Combination]) = ",")
RETURN
IF(RemoveMultipleCommas <> ",",
MID(RemoveMultipleCommas,
1 + LeftComma,
LEN(RemoveMultipleCommas) - RightComma - LeftComma
), "")
Finally, let's modify the customers measure a bit so it can subtotal.
customers =
VAR Summary = SUMMARIZE(Table1,
Table1[customer_id],
"ProductList",
CONCATENATEX(VALUES(Table1[product]), Table1[product], ","))
VAR CustomerCount = SUMX(Summary, IF([ProductList] = MAX(Table2[Delimited]), 1, 0))
VAR Total = IF(ISFILTERED(Table2[Delimited]), CustomerCount, COUNTROWS(Summary))
RETURN IF(Total = 0, BLANK(), Total)
The Total variable gives the total customer count for the total. Note that I've also set zeros to return as blank so that you don't need to filter out zeros (it will automatically hide those rows).
You can also try this measure to calculate the result.
[Count Of Customers] :=
VAR var_products_selection_count = DISTINCTCOUNT ( Sales[product] )
VAR var_customers = VALUES ( Sales[customer_id] )
VAR var_customers_products_count =
ADDCOLUMNS(
var_customers,
"products_count",
VAR var_products_count =
COUNTROWS (
FILTER (
CALCULATETABLE ( VALUES ( Sales[product] ) ),
CONTAINS (
Sales,
Sales[product],
Sales[product]
)
)
)
RETURN var_products_count
)
RETURN
COUNTROWS (
FILTER (
var_customers_products_count,
[products_count] = var_products_selection_count
)
)
I think I've found a better solution/workaround that doesn't require precomputing all possible combinations. The key is to use a rank/index as a base column and then built off of that.
Since the customer_id is already nicely indexed starting from 1 with no gaps, in this case, I will use that, but if it weren't, then you'd want to create an index column to use instead. Note that there cannot be more distinct product combinations within a given filter context than there are customers since each customer only has a single combination.
For each index/rank we want to find the product combination that is associated with it and the number of customers for that combination.
ProductCombo =
VAR PerCustomer =
SUMMARIZE (
ALLSELECTED ( Table1 ),
Table1[customer_id],
"ProductList",
CONCATENATEX ( VALUES ( Table1[product] ), Table1[product], "," )
)
VAR ProductSummary =
SUMMARIZE (
PerCustomer,
[ProductList],
"Customers",
DISTINCTCOUNT ( Table1[customer_id] )
)
VAR Ranked =
ADDCOLUMNS (
ProductSummary,
"Rank",
RANKX (
ProductSummary,
[Customers] + (1 - 1 / RANKX ( ProductSummary, [ProductList] ) )
)
)
VAR CurrID =
SELECTEDVALUE ( Table1[customer_id] )
RETURN
MAXX ( FILTER ( Ranked, [Rank] = CurrID ), [ProductList] )
What this does is first create a summary table that computes the product list for each customer.
Then you take that table and summarize over the distinct product lists and counting the number of customers that have each particular combination.
Then I add a ranking column to the previous table ordering first by the number of customers and tiebreaking using a dictionary order of the product list.
Finally, I extract the product list from this table where the rank matches the index/rank of the current row.
You could do a nearly identical measure for the customer count, but here's the measure I used that's a bit simpler and handles 0 values and the total:
Customers =
VAR PerCustomer =
SUMMARIZE (
ALLSELECTED ( Table1 ),
Table1[customer_id],
"ProductList",
CONCATENATEX ( VALUES ( Table1[product] ), Table1[product], "," )
)
VAR ProductCombo = [ProductCombo]
VAR CustomerCount =
SUMX ( PerCustomer, IF ( [ProductList] = ProductCombo, 1, 0 ) )
RETURN
IF (
ISFILTERED ( Table1[customer_id] ),
IF ( CustomerCount = 0, BLANK (), CustomerCount ),
DISTINCTCOUNT ( Table1[customer_id] )
)
The result looks like this

Custom aggregate column in power bi matrix

I'm trying to create a matrix in a Power BI report summarizing Salesperson performance sliced in a number of different ways.
I know how to create a matrix with Rows - Salesperson, Columns - Product Type, and Values - count of Sales which will show the number of Sales per Salesperson per Product Type, but I'd like also be able to do the following:
Add an additional column set to pivot on (e.g. Sales Year), so that I could see count of Sales pivoted by both Product Type and Year in the same table side by side (i.e., not nested).
Add additional summary columns to my matrix showing values such as average Sale Amount by Salesperson, % of total number of Sales by Salesperson.
For clarity, I'd imagine that this would result in a matrix where the column headers read: Salesperson, Product 1, Product 2, ..., Year 1, Year 2, ..., Total Sales Count, Average Sales Amount, % of Total Sales Count. See image link below (I don't have the reputation points to include the actual image yet)
I recognize that I can do this by creating measures which effectively replicate how the matrix is splitting out the values and adding each measure as a value (no Columns), but I don't want to have to create new measures and update the matrix every year or every time we add a new Product Type.
I've also looked at custom visuals on the Power BI marketplace, but didn't see any that would achieve this.
It's possible to do this, but not super easy. You'll need a measure with a SWITCH as well as a table for your headers.
You can create a header table along these lines:
Header =
UNION (
SUMMARIZE ( Sales, Sales[Product], "Group", "By Product", "Index", 1 ),
SUMMARIZE ( Sales, Sales[Year], "Group", "By Year", "Index", 2 ),
DATATABLE (
"Header", STRING,
"Group", STRING,
"Index", INTEGER,
{
{ " Total", "Summarizations", 3 },
{ "% of Total Sales", "Summarizations", 3 },
{ "Avg Sale Size", "Summarizations", 3 }
}
)
)
Which will look like this:
Header, Group, Index,
Product 1, By Product, 1,
Product 2, By Product, 1,
2016, By Year, 2,
2017, By Year, 2,
2018, By Year, 2,
Total, Summarizations, 3,
% of Total Sales, Summarizations, 3,
Avg Sale Size, Summarizations, 3
This table will automatically expand when more products or years are added.
(Note: The Index column is so I can order them properly using Sort by Column.)
Once you have that, you just need to put Group and Header on the columns of a matrix visual and Salesperson on the rows, with a switching measure in the values.
Measure =
VAR Val =
SWITCH (
SELECTEDVALUE ( Header[Group] ),
"By Product", CALCULATE (
SUM ( Sales[Amount] ),
FILTER ( Sales, Sales[Product] = MAX ( Header[Header] ) )
),
"By Year", CALCULATE (
SUM ( Sales[Amount] ),
FILTER ( Sales, Sales[Year] = VALUE ( MAX ( Header[Header] ) ) )
),
SWITCH (
SELECTEDVALUE ( Header[Header] ),
"% of Total Sales", DIVIDE (
SUM ( Sales[Amount] ),
CALCULATE ( SUM ( Sales[Amount] ), ALL ( Sales ) )
),
"Avg Sale Size", AVERAGE ( Sales[Amount] ),
SUM ( Sales[Amount] )
)
)
RETURN
IF (
SELECTEDVALUE ( Header[Header] ) = "% of Total Sales",
FORMAT ( Val, "0.0%" ),
FORMAT ( Val, "0.0" )
)
Each different group gets its own calculation and we have to use the FORMAT function to force the table to format the percentage function properly.
(Note: If you have slicers or filtering, you probably want to use ALLSELECTED where I used ALL above.)
Here's what my table looks like (not the exact same data but similar structure)
and here's the PBIX file I created for this:
https://drive.google.com/file/d/1qxc5p53MgmOm-NH3EcivkZLhLeEHpr4R/