DAX: How do I write an IF statement to return a calculation for multiple (specific) values selected? - powerbi

This is driving me nuts. Let's say we want to use a slicer which has two distinct values to choose from a dimension. There is A and B.
Let us also say that my Fact table is connected to this dimension, however it has the same dimension with more options.
My slicer now has A, B and (Blank). No biggie.
Let's now say I want to list out all of the possible calculation outcomes by selecting the slicer in a DAX formula, but in my visual I need all those outcomes to be listed in an IF() branched formula:
I can list out A:
IF(MAX(SlicerDim[Column]) = "A", CALCULATE([Calculation], SlicerDim[Column] = "A")
I can list out B:
IF(MAX(SlicerDim[Column]) = "A", CALCULATE([Calculation], SlicerDim[Column] = "A")
I can list out the (Blank) calculation too:
CALCULATE([Calculation], SlicerDim[Column] = Blank())
And I've managed to get a calculation out of it even when all of the slicer elements are on or off, using:
NOT(ISFILTERED(SlicerDim[Column])), CALCULATE([Calculation], SlicerDim[Column] = "A" || SlicerDim[Column] = "B")
Notice I need this IF() branch to actually return a calculation using A & B values, so now I have returns for when A or B or (Blank) or All or None are selected; BUT NOT when multiple values of A & B are selected!
How do I write out this IF() branch for it to return the same thing, but when both A & B are selected? Since there are only two real options in the slicer - I managed to use MIN() and MAX() get it to work by using their names or Index numbers.
IF((MIN(SlicerDim[Column]) = "A" && MAX(SlicerDim[Column]) = "B") || NOT(ISFILTERED(Paslauga[Paslauga])), CALCULATE([Calculation], SlicerDim[Column] = "A" || SlicerDim[Column] = "B")
BUT - I want a more understandable/robust/reusable formula, so that I could list out many selectable values from the slicer and have it return a calculation for specifically selected slicer values.
Please, help.
I've been searching high and low and there seems to not be an easy way to fix this albeit scraping the IF route and just using a damn slicer for this type of dilemma.
TL;DR:
How do I write an IF() branch calculation using DAX to get an outcome when All/None or non-blank or Specific slicer values are selected?
My best effort:
I am looking to improve the first IF() branch to not have to use MIN/MAX, because I would like to be able to reuse this type of formula if there were more than two real options in the slicer:
IF_branch =
IF((MIN(SlicerDim[Column]) = "A" && MAX(SlicerDim[Column]) = "B" || NOT(ISFILTERED(SlicerDim[Column])), CALCULATE([Calculation], SlicerDim[Column] = "A" || SlicerDim[Column] = "B"),
IF(MAX(SlicerDim[Column]) = "A", CALCULATE([Calculation], SlicerDim[Column] = "A"),
IF(MAX(SlicerDim[Column]) = "B", CALCULATE([Calculation], SlicerDim[Column] = "B"),
CALCULATE([Calculation], SlicerDim[Column] = BLANK()))))

Think what you are looking for is CONTAINS and VALUES
VALUES will give you the distinct current selection in scope.
CONTAINS lets you check if a table contains any row with a set of values.
[]
Formulas:
selected Scenarios = CONCATENATEX(VALUES(DimScenario[ScenarioName]);[ScenarioName];";")
Contains Forecast and Budget? =
IF(
CONTAINS(VALUES(DimScenario[ScenarioName]);[ScenarioName];"Forecast") &&
CONTAINS(VALUES(DimScenario[ScenarioName]);[ScenarioName];"Budget")
;"Yes"
;"No"
)

Related

Filter data using IF Statement in Tableau

I have a data source in tableau that looks something similar to this:
SKU Backup_Storage
A 5
A 1
B 2
B 3
C 1
D 0
I'd like to create a calculated field in tableau that performs a SUM calculation IF the SKU column contains the string 'A' or 'D' , and to perform an AVERAGE calculation if the SKU column contains the letters 'C' or 'B'
This is what I am doing:
IF CONTAINS(ATTR([SKU]),'A') or
CONTAINS(ATTR([SKU]),'D')
THEN SUM([Backup_Storage])
ELSEIF CONTAINS(ATTR([SKU]),'B') or
CONTAINS(ATTR([SKU]),'C')
THEN AVG([Backup_Storage])
END
UPDATE - desired output would be:
SKU BACKUP
A, D 6 (This is the SUM OF A and D)
B, C 2 (This is the AVG of B and C)
The calculation above shows as valid, however, I see NULLS in my data source table.
Any suggestion is appreciated.
I have named the calculated field:
SKU_FILTER_CALCULATION
Basically, IF THEN ELSE condition works when one test that is either TRUE/FALSE. Your specified condition is not a proper use case of IF THEN ELSE because SKUs can take all possible values. See it like this..
your data
SKU Backup_Storage
A 5
A 1
B 2
B 3
C 1
D 0
Let's name your calc field as CF, then CF will take value A in first row and will output SUM(5) = 5. For second row it will output sum(1) = 1, for third and onward rows it will output as avg(2) = 2, avg(3) = 3, avg(1) and sum(0) respectively. all these values just equals [Backup_storage] only and I'm sure that this you're not trying to get.
If instead you are trying to get sum(5,1,0) + avg(2,3,1) (obviously i have assumed + here) which equals 8 i.e. one single value for whole dataset, please proceed with this calculated field..
SUM(IF CONTAINS([SKU], 'A') OR CONTAINS([SKU], 'D')
THEN [Backup storage] END)
+
AVG(IF CONTAINS([SKU], 'B') OR CONTAINS([SKU], 'C')
THEN [Backup storage] END)
This will return an 8 when put to view
Needless to say, if you want any other operator instead of + you have to change that in CF accordingly
As per your edited post, I suggest a different methodology. Create diff groups where you want to perform different aggregations
Step-1 Create groups on SKU field. I have named this group as SKUG
Step-2 create a calculated field CF as
SUM(ZN(IF CONTAINS([SKU], 'A') OR CONTAINS([SKU], 'D')
THEN [Backup storage] END))
+
AVG(ZN(IF CONTAINS([SKU], 'B') OR CONTAINS([SKU], 'C')
THEN [Backup storage] END))
Step-3 get your desired view
Good Luck

Power BI - Power Query Editor: Remove All Duplicates (Don't leave any rows that were part of the duplicate)

So, I know how to remove duplicates which leave one row behind. What I want to do is remove all of the rows associated with a duplicate, because we don't know which of the duplicates we want to keep, and for our purposes therefore don't want any of them in our table. There are only two columns. One column contains the duplicates. The second has unique values per duplicate, but we don't want any of them to remain.
Thank you.
Here is a possible workaround. Use Table.Group to count the duplication, then retain only unique entries using Table.SelectRows.
let
Source = Table.FromRecords({
[a = "A", b = "a"], // < duplicated
[a = "B", b = "a"],
[a = "A", b = "a"] // < duplicated
})
in
Table.SelectRows(
Table.Group(Source, {"a", "b"}, {"Count", Table.RowCount}),
each [Count] = 1
)
/*
* Output
*
* a b Count
* --- --- -----
* B a 1
*/

How do I create calculated column in power bi?

I am new to Power BI and was wondering if someone can help me.
I have a table
A B Status
---------------------------
Asset1 B1 Compliant
Asset1 B2 N/A
Asset2 B1 Non- Compliant
Asset2 B2 Compliant
Asset3 B1 Compliant
Asset3 B2 Compliant
I have to find the Asset which are 100% compliant(Count of Asset where status of all the rows of Column B is Compliant and not non Compliant and we need to ignore N/A.
Out put I want
A 100%Compliant
Asset1 Y
Asset2 N
Asset3 Y
Thanks
You can create an extra column in your table:
100% Cpmpliant =
var asset = Compliant[A]
var allRows = CALCULATE(COUNTROWS(Compliant); FILTER(Compliant; Compliant[A] = asset && Compliant[Status] <> "N/A"))
var compliantRows = CALCULATE(COUNTROWS(Compliant); FILTER(Compliant; Compliant[A] = asset && Compliant[Status] = "Compliant"))
return if (allRows = compliantRows; "Y";"N")
This calculates the rows of the asset without the N/A and compares it against teh rowcount of the compliant. If this is equal, they are all compliant-
Next you can create a visual with two columns ass below:
Edited:
You can create a measure:
IsCompliant =
VAR NumNonCompliant = CALCULATE(COUNTAX('Table', [B]), 'Table'[Status] = "Non - Compliant")
RETURN IF(NumNonCompliant = 0, "Y", "N")
The variable NumConCompliant calculates the number of rows with status = "Non - Compliant". Then it is compared with 0 to find any non-compliance.
Then the measure returns the state of "A" in the given context. This gives you the flexibility of assigning compliance measure to a combination of assets. For example if you filter data on "A = Asset1", the result would be "Y", and (A = Asset1 || A = Asset2) results in a "N". (Since the combination of Asset1 & Asset2 are non-compliant).
Refer to this doc about measures and contexts.

How to Return Text with IF Function in an Array

In Google Sheets, I'm trying to query a column and look for a state abbreviation, and if that abbreviation is a match, then "East" if not then "West"
Wanting to return text values in my column based on state abbreviation. We have territory manager split into two domains--East and West. So, trying to easily sort my data by East/West.
Here's what I have:
=IF(M:M={"AL", "CA", "DE","FL","GA","IA","KY","ME","MD","MA","MN","MS","NH","NJ","NY","ND","RI","SD","TN","VT","VA","WV","WI"},"East","West")
But, when I fill down, it just fills down East, and does not seem to actually query M:M
Thoughts?
Not the cleanest code, but this should work:
=ARRAYFORMULA(IF(LEN(A:A), IF((A:A = "foo")+(A:A = "bar") = 1, "WEST", "EAST"), ))
To use IF with an OR in an ARRAYFORMULA, you evaluate the column with 1s and 0s. The A:A = "foo" will evaluate to 1 if foo is in the cell. So if one of your OR criteria is in the cell, the total value in the IF will be 1.
You have a lot of criteria so writing each of them in will take a while ...
E.g. IF( (A:A = "AL") + (A:A = "CA") ... (A:A = "WI") = 1, "East", "West")
Use ISERROR/MATCH():
=IF(ISERROR(MATCH(M:M,{"AL", "CA", "DE","FL","GA","IA","KY","ME","MD","MA","MN","MS","NH","NJ","NY","ND","RI","SD","TN","VT","VA","WV","WI"},0)),"West","East")

How to compare values in pandas between two different columns?

My Table:
A Country Code1 Code2
626349 US 640AD1237 407223
702747 NaN IO1062123 407255
824316 US NaN NaN
712947 US 00220221 870262123
278147 Canada 721AC31234 109123
278144 Canada NaN 7214234321
278142 Canada 72142QW134 109123AS12
Here in the above table I need to check country and code.
I want a 5th column with correct or wrong, pseudocode:
If 'Country' == 'US' and (length(Code1) OR length(Code2) == 9):
Add values to 5th column as correct.
else:
Add values to 5th column as incorrect.
If 'Country' == 'Canada' and (length(Code1) OR length(Code2) == 10):
Add values to 5th column as correct.
else:
Add values to 5th column as incorrect.
if no values are there either in Country or Code Column than insufficient information.
I am not able to understand how should I do this in pandas. Please help. Thanks.
I tried to first find the length of rows of Code1 and Code2 and store it in different df but after that I am not able to Compare the different set of data as what I need to do.
Len1 = df.Code1.map(len)
Len2 = df.Code2.map(len)
LengthCode = pd.DataFrame({'Len_Code1': Len1,'Len_Code2': Len2})
Please tell me the better way of how to do this in single dataframe if possible.
I tried this
df[(df.Country == 'US') & ((df.Code1.str.len() == 9)|(df.Code2.str.len() == 9))|(df.Country == 'Canada') & ((df.Code1.str.len() == 10)|(df.Code2.str.len() == 10))]
But it is getting long and I will not be able to write for many countries.
This will give you a 'is_correct' boolean column:
code_lengths = {'US':9, 'Canada':10}
df['correct_code_length'] = df.Country.replace(code_lengths)
df['is_correct'] = (df.Code1.apply(lambda x: len(str(x))) == df.correct_code_length) | (df.Code2.apply(lambda x: len(str(x))) == df.correct_code_length)
You will need to populate the code_lengths dictionary with more countries as necessary.