Convert comma separated text to a list of numbers - powerbi

In Power BI, I have created a DAX query created with a var giving comma-separated text using CONCATENATEX function.
Output like
Var = "1,2,3,4,5,6"
Now I want to search this var into my table column with syntax
Table[col] in {var}.
It is throwing an error.
I even tried converting the column to string with syntax
Convert(table[col], string) in {var}
The error is removed but the data doesn't match with column data.

I found this Power BI community thread that is essentially the same question.
The solution is to convert the string into a path object.
Here's the code from the link:
Measure 3 =
VAR mymeasure =
SUBSTITUTE ( [Measure], ",", "|" )
VAR Mylen =
PATHLENGTH ( mymeasure )
VAR mytable =
ADDCOLUMNS (
GENERATESERIES ( 1, mylen ),
"mylist", VALUE ( PATHITEM ( mymeasure, [Value] ) )
)
VAR mylist =
SELECTCOLUMNS ( mytable, "list", [mylist] )
RETURN
CALCULATE ( COUNTROWS ( Table1 ), Table1[ID] IN mylist )
There's a bit of redundancy in the above, so I'd probably condense it a bit and write it like this:
SomeMeasureFilteredByVar =
VAR PathVar = SUBSTITUTE ( [Var], ",", "|" )
VAR VarList =
SELECTCOLUMNS (
GENERATESERIES ( 1, PATHLENGTH ( PathVar ) ),
"Item", VALUE ( PATHITEM ( PathVar, [Value] ) )
)
RETURN
CALCULATE ( [SomeMeasure], 'Table'[ID] IN VarList )
Edit: To just create a calculated table, you can skip the last step:
TableFromString =
VAR PathVar = SUBSTITUTE ( "1,2,3,4,5,6", ",", "|" )
RETURN
SELECTCOLUMNS (
GENERATESERIES ( 1, PATHLENGTH ( PathVar ) ),
"Item", VALUE ( PATHITEM ( PathVar, [Value] ) )
)
Note that it is not possible to create a calculated table that is dynamically responsive to report filters and slicers. Materialized calculated tables are only calculated once when the data loads, not every time you adjust a filter or slicer.
Therefore, you can use a measure in the table instead of the string "1,2,3,4,5,6" but the table output will be the same regardless of what the measure returns within different filter contexts.

Related

arguments in generate series cannot be blank error

i am trying to apply levenshtein distance to 2 columns, tables and getting error in generate series cannot be blank.Here is my code.
Measure =
VAR SlicerText =
SELECTEDVALUE ( 'Slicer Table'[TestColumn] )
VAR TableText =
SELECTEDVALUE ( 'Table'[TestColumn] )
VAR length =
MAX ( LEN ( SlicerText ), LEN ( TableText ) )
VAR TestTable =
ADDCOLUMNS (
GENERATESERIES ( 1, length, 1 ),
"InSlicer", MID ( SlicerText, [Value], 1 ),
"InTable", MID ( TableText, [Value], 1 )
)
RETURN
COUNTROWS ( FILTER ( TestTable, [InSlicer] = [InTable] ) )
/ COUNTROWS ( TestTable )
With a little effort you could have figured this out yourself:
The error message tells you that one of the parameters of GENERATESERIES() is blank. This can ONLY be the length variable.
length is blank when both variables SlicerText and TableText are blank.
both variables refer to the SELECTEDVALUE() function, which returns blank if none or more than one rows are selected and you didn't provide an alternateResult, see the official documentation here: SELECTEDVALUE
Bottom line: Make shure you have exactly one row selectd in 'Slicer Table' and 'Table'.
This is as much help as you can get, since you didn't share a minimal, reproducible example as recommended by StackOverflow.

DAX: Filter, group by and count distinct values in Power BI

How can I filter the table by Category = Animal, then group by Class, and count the distinct id for each group?
So far I can only group by and count distinct values:
output = SUMMARIZE(my_table, my_table[Class], "Distinct Count", DISTINCTCOUNT(my_table[Id]))
I tried:
output = CALCULATETABLE(SUMMARIZE(my_table, my_table[Class]), DISTINCTCOUNT(my_table[Id]), FILTER(my_table, my_table[Category ] = "Animal"))
which caught error:
The True/False expression does not specify a column. Each True/False expressions used as a table filter expression must refer to exactly one column.
I also tried the way suggested by this post but it only counts the number of rows in the table rather than the distinct number of Id.
Try this:
output =
SUMMARIZECOLUMNS (
my_table[Class],
TREATAS ( { "Animal" }, my_table[Category] ),
"Distinct Count", DISTINCTCOUNT ( my_table[Id] )
)
Another option:
output =
CALCULATETABLE (
ADDCOLUMNS (
VALUES ( my_table[Class] ),
"Distinct ID", CALCULATE ( DISTINCTCOUNT ( my_table[Id] ) )
),
my_table[Category ] = "Animal"
)
SUMMARIZECOLUMNS version is generally an optimized way of writing the code so you should prefer that one. I have included ADDCOLUMNS/CALCULATETABLE construct only for the learning purpose.
Check this out: Filter SUMMARIZECOLUMNS
You filter in this way:
VAR __MyFilterTable = FILTER( ALL(T[category]), T[category] = "animal" )
RETURN
SUMMARIZECOLUMNS (
T[category],
__MyFilterTable
)
Or even shorter:
VAR __MyFilterTable = TREATAS ({"animal"}, T[category] )
RETURN
SUMMARIZECOLUMNS (
T[category],
__MyFilterTable
)

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.

How to count when string value filtered by A is also equal to string value filtered by B

I am currently working in Power BI and need to write the DAX code for counting number of string values when string filtered by A is also appearing when same string filtered by B.
I have tried various of codes and everything that came in my mind, but I am lacking experience in comparing values in DAX, and kinda beat at the moment.
eg.
When looking at table, I need to count (distinct) when John, Adam, Julie from A is also appearing in B, which is in this case is 3.
I will be happy if someone has any ideas or directions for me to seek into!
Assuming your table name is "Data":
Count of Common Names =
VAR A_Names =
CALCULATETABLE ( VALUES ( Data[Name] ), Data[Filter] = "A" )
VAR B_Names =
CALCULATETABLE ( VALUES ( Data[Name] ), Data[Filter] = "B" )
VAR Common_Names =
INTERSECT ( A_Names, B_Names )
RETURN
COUNTROWS ( Common_Names )
How it works:
First, we create a table of distinct names for filter A.
Second, we do the same for filter B.
Finally, we find what names exist in both tables, by finding their intersection.
Edit:
To calculate costs for common names, modify the above measure:
Cost of A given B =
VAR A_Names =
CALCULATETABLE ( VALUES ( Data[Name] ), Data[Filter] = "A" )
VAR B_Names =
CALCULATETABLE ( VALUES ( Data[Name] ), Data[Filter] = "B" )
VAR Common_Names =
INTERSECT ( A_Names, B_Names )
RETURN
CALCULATE ( SUM ( Data[Cost] ), Common_Names, Data[Filter] = "A" )
This will count the number of distinct names, having more than one distinct value:
Names with Multiple Distinct Values =
COUNTROWS (
FILTER (
SUMMARIZECOLUMNS (
MyTable[Name],
"Distinct Values",
DISTINCTCOUNT ( MyTable[Values] )
),
[Distinct Values] > 1
)
)

Find the last value after the dot in DAX e.g. in value1.value2.value3 finds value3

I have a column with a dotted value e.g
project.phase.task
project.task
project.phase.subphase.task
in each instance I want the last doted value.
I am using the DAX function:
lastVal =
var i = FIND(".",'My Table'[wbs],1,-1)
return
if(i>0,mid('My Table'[wbs],i+1,99),"")
There is no FindLast function. How would I simulate it?
This would be a similar problen to finding a file extension in a file name or path.
You don't need to do this with DAX. You can use Split Column function of the Query Editor to get the part of the text after the right-most dot.
You can do this with DAX.
As a calculated column:
lastVal =
PATHITEMREVERSE (
SUBSTITUTE (
'My Table'[wbs],
".",
"|"
),
1
)
As a measure:
lastValMeasure =
VAR MyString =
IF (
HASONEVALUE ( 'My Table'[wbs] ),
FIRSTNONBLANK ( 'My Table'[wbs], 1 ),
BLANK()
)
RETURN
PATHITEMREVERSE (
SUBSTITUTE (
MyString,
".",
"|"
),
1
)
You can turn the string into an indexed list of characters and then take the characters after the maximally indexed ..
This should work as a calculated column:
lastVal =
VAR String = 'My Table'[wbs]
VAR StringLength = LEN ( String )
VAR StringToTable =
ADDCOLUMNS (
GENERATESERIES ( 1, StringLength ),
"Char", MID ( String, [Value], 1 )
)
VAR LastDot = MAXX ( FILTER ( StringToTable, [Char] = "." ), [Value] )
RETURN
RIGHT ( String, StringLength - LastDot )
If you need it as a measure, then simply adjust the String variable to take the appropriate aggregate. For example, MAX('My Table'[wbs]) or FIRSTNONBLANK('My Table'[wbs], 'My Table'[wbs]).