SELECTEDVALUE not returning expected value - powerbi

I have created this table in Power BI:
DimProduct = UNION(
ROW("ProductId", 1, "Product", "AB","ProductType","A"),
ROW("ProductId", 2, "Product", "AC","ProductType","A"),
ROW("ProductId", 3, "Product", "AD","ProductType","A"),
ROW("ProductId", 4, "Product", "BB","ProductType","B"),
ROW("ProductId", 5, "Product", "BC","ProductType","B")
)
Then I created this table:
DimProductSelectedType =
VAR vSelectedProduct=
SELECTEDVALUE('DimProduct'[Product])
RETURN
ROW("Col1",vSelectedProduct)
I dropped DimProduct[Product] into a slicer
I dropped DimProductSelectedType into a list
I expect that when I pick one product from the product slicer, it will appear in the list. But the list always remains blank.
I had thought that SELECTEDVALUE would reflect any single value picked in a slicer
That's my immediate problem, and this can be summarized as
Table columns that use DAX calcs are evaluated at import time. Measure are evaluated at runtime
What I'm actually working towards is:
Pick a product in a slicer
Identify that products product type
Show visualisations comparing selected product compared to all other products within that product type
I actually started with this and now I'm working my way back.
DimProductTypeSelected =
VAR vSelectedProduct=
SELECTEDVALUE('DimProduct'[Product])
VAR vSelectedProductType=
SUMMARIZE(
FILTER(
ALLSELECTED(DimProduct),
DimProduct[Product]=vSelectedProduct
),
DimProduct[ProductType]
)
RETURN
FILTER(
ALLSELECTED(DimProduct),
DimProduct[ProductType]=vSelectedProductType
)

When you select item in a slicer it already creates fitler context on other visuals, so there is no need to overwrite it manually. What you would need to do is to create a fitler context for all products, e.g. by using ALL or ALLSELECTED for the comparators. But in order for this to be dynamic you need to use measures, tables are static and do not recalculate with UI changes.
To explain why you get your results with your current approach - tables are refreshed once and do not change afterwards. Therefore vSelectedProduct always returns blank, as at the moment of refreshing this table there is no filter context on the DimProduct[Product], so it defaults to blank
If you create a measure Measure = SELECTEDVALUE('DimProduct'[Product]) and put DimProduct[Product] into a slicer it will show the selected product for a single select and blank for multiselect (or all values)
EDIT
Regarding the second part of your question - selecting a product will create a filter context only for that product in the other visuals. Then you could use e.g.:
CountRowsPerType =
VAR vSelectedType =
SELECTEDVALUE('DimProduct'[ProductType])
RETURN
CALCULATE( COUNTROWS(DimProduct), ALL(DimProduct[Product]), 'DimProduct'[ProductType] = vSelectedType )
which will return count for all the products of that type even though the visual will only show the selected product

Related

Power BI DAX How to add column to a calculated table that summarizes another

I Have a TestTable that summarizes a table Receipts on the Month column and adds a column that counts the number of times (occurence) that each month appears in the Receipts Table.
TestTable = SUMMARIZE(Receipts, Receipts[Month], "TotalReceiptsIssuedInThisMonth", SUM(Receipts[Receipts Issued]), "OccurenceOfMonth", COUNT(Receipts[Month]))
I want to add two columns to this TestTable which will tell me the following:
Sum the TotalReceiptsIssuedInThisMonth of the TestTable and show the
value in each row
For each Month (row), divide the, TotalReceiptsIssuedInThisMonth by the SumOfTotalReceiptsIssued
I know I can click "New Column" and use these formulas:
AvgPercentageReceiptsIssuedInThisMonth = TestTable[TotalReceiptsIssuedInThisMonth]/TestTable[TotalReceiptsIssued]
TotalReceiptsIssued = SUM(TestTable[TotalReceiptsIssuedInThisMonth])
However, I need to integrate those two columns directly into the original TestTable formula to make it all happen in one step for use as a variable in the original Receipts table (otherwise I end up with circular logic if I try using relationships).
I've tried the following:
TestTable = SUMMARIZE(PPTs, PPTs[Month], "TotalReceiptsIssuedInThisMonth", SUM(PPTs[PPTs Issued]), "OccurenceOfMonth", COUNT(PPTs[Month]), "TotalReceiptsIssued", SUM(TestTable[TotalReceiptsIssuedInThisMonth]), "AvgPercentageReceiptsIssuedInThisMonth", TestTable[TotalReceiptsIssuedInThisMonth]/TestTable[TotalReceiptsIssued])
but this returns an error saying "A single value for column 'TotalReceiptsIssuedInThisMonth' in table 'TestTable" cannot be determined. This can happen when a measure formula refers to a column that contains many values without specifying an aggregation such as min, max, count, or sum to get a single result." and I've tried:
TestTable =
VAR first = SUMMARIZE(Receipts, Receipts[Month], "TotalReceiptsIssuedInThisMonth", SUM(Receipts[Receipts Issued]), "OccurenceOfMonth", COUNT(Receipts[Month]))
VAR second = SUM(TestTable[TotalReceiptsIssuedInThisMonth])
VAR third = first[TotalReceiptsIssuedInThisMonth]/second
RETURN
third
But this returns an error saying "The variable'first' cannot be used in current context because a base table is expected."
So my question is, how do I go about combining these three steps into one DAX formula?
I would do something like this. I prefer ADDCOLLUMN(SUMMARIZE()...), because it helps to avoid a miscontexting. As you need a var table, then you need the CALCULATE in ADDCOLUMNS, as it adds the row context.
VAR TestTable =
ADDCOLUMNS(
SUMMARIZE(
Receipts
,Receipts[Month]
)
,"TotalReceiptsIssuedInThisMonth",CALCULATE(SUM(Receipts[Receipts Issued]))
,"OccurenceOfMonth", CALCULATE(COUNT(Receipts[Month]))
,"TotalReceiptsIssued ",SUM(Receipts[Receipts Issued])
)
RETURN
ADDCOLUMNS(
TestTable
,"AvgPercentageReceiptsIssuedInThisMonth"
,DIVIDE([TotalReceiptsIssuedInThisMonth],[TotalReceiptsIssued])
)
Check out More regarding the use of DAX to create a table
https://www.advancelearnlinux.com/how_to_create-table-in-microsoft-power-bi-using-dax-function/

How to select the last value of the day with DAX in Power BI

I am new to power BI and stuck with an issue. I have my model as follows:
Date Dimension
Measurement Fact
The date column in Date Dimension is link to measuredate in Measurement Fact
Below is a sample data:
NB: In edit query, I have changed the type of measuredate to Date only.
I have tried the measure below but it doesn't work the way I want. It will sum all the values of the day but what I want is the last value of the day:
day_fuel_consumption =
CALCULATE (
SUM ( measurement[measurementvalue] ),
FILTER (
measurement,
measurement[metername] = "C-FUEL"
&& measurement[measuredate] = MAX ( measurement[measuredate] )
)
)
My Goal is to get 29242, i.e the last value of the day. Remember that measuredate is a Date field and not Datetime (I changed to Date field so that my Year and Month filter can work correctly). I have changed the type in edit query.
Changing your measure to use a variable could be the solution:
DFC =
var maxDate = MAX(measurement[measuredate])
return
CALCULATE(
SUM(measurement[measurementvalue]),
measurement[measuredate] = maxDate
)
However, you should keep the datetime format for measureDate. If you don't want to see the time stamp just change the format I power bi. Otherwise power bi will see two values with max date and sum them, instead of taking the last one.
Well, if you want to avoid creating a measure, you could drag the fields you are filtering over to the visual filters pane. Click your visual, and scroll a tiny bit and you will see the section I am referring to. From there, just drag the field you are trying to filter In this case, your value. Then select "Top N". It will allow you to select a top (number) or bottom (number) based on another field. Strange enough, it does allow you to do top value by top value. It doesn't make sense when you say it out loud, but it works all the same.
This will show you the top values for whatever value field you are trying to use. As an added bonus, you can show how little or how many you want, on the fly.
As far as DAX goes, I'm afraid I am a little DAX illiterate compared to some other folks that may be able to help you.
I had to create two separate measures as shown below for this to work as I wanted:
max_measurement_id_cf = CALCULATE(MAX(measurement[measurementid]), FILTER(measurement, measurement[metername] = "C-FUEL"))
DFC =
var max_id_cf = [max_measurement_id_cf]
return
CALCULATE(SUM(measurement[measurementvalue]), measurement[measurementid] = max_id_cf)

Display Matched and Non Matched Values based on a slicer value Power BI

I am working on a Viewership table which tells which customer watches which asset. Based on the asset filter, I need to display the customers who watched the show & customers who didn't watched the show. below is my example table
If the asset_id selected as 1 in the slicer, the desired output will be as below
I have tried creating a cross-join table with asset_id and customer_id , but that approach taking much time with large data. Request the experts here to suggest the best optimal solution to achieve this.
First, create a new table "Asset":
This table contains unique assets, and we will use it to create a slicer that affects DAX measure but does not affect the visual (table). To achieve that, the Asset table must be disconnected from the Viewership table (no relationships).
In your viewership table, I just renamed "asset" to "asset_id", to be consistent:
Next, create a measure:
Status =
VAR Selected_Asset = SELECTEDVALUE(Asset[asset_id])
VAR Customer_Asset = SELECTEDVALUE(Viewership[asset_id])
RETURN
IF(Customer_Asset = Selected_Asset, "Watched", "Not Watched")
Result:
Slicer here is created from the "Asset" table, and table is a table visual with customer_id and asset_id from the Viewership table (set them as "don't summarize" values). I turned off "total", assuming you don't need it.
This design requires to set Asset slicer to "single selection" mode, to make sure that you are only getting one value from it. If you want the model to work with multi-select slicer, change DAX measure as follows:
Multi Status =
VAR Selected_Assets = ALLSELECTED(Asset[asset_id])
VAR Customer_Asset = SELECTEDVALUE(Viewership[asset_id])
RETURN
IF(Customer_Asset IN Selected_Assets, "Watched", "Not Watched")
Result:
Edit:
To make it work at the customer level:
Customer Status =
VAR Selected_Assets = ALLSELECTED(Asset[asset_id])
VAR Customer_Assets = VALUES(Viewership[asset_id])
VAR Assets_Watched = COUNTROWS(INTERSECT(Customer_Assets, Selected_Assets))
RETURN
IF(Assets_Watched > 0, "Watched", "Not Watched")
Result:
Explanation: store selected assets in a table variable. Then, store assets visible per customer in another table variable. Find an intersect of the two tables (what they have in common), and count intersect rows. If none - not watched, otherwise watched. If you want, you can actually display the number of movies watched (just return "Assets_Watched" instead of IF statement).

Filtering other tables based on cross-highlighting a filtered measure

I want to count records in a certain condition and allow people to filter down to the relevant records, but selecting a measure value (which filters so it only counts certain rows) isn't cross-filtering others as I'd expect. Maybe ths isn't possible or maybe I'm just doing it wrong, but I'd appreciate help.
I have a single table:
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45Wci4tLsnPTS1SMFTSUTJUitVBEjICChmgChljCplgajSFCMUCAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [#"Customer Name" = _t, #"Ordered Recently" = _t]),
#"Change to INT" = Table.TransformColumnTypes(Source,{{"Ordered Recently", Int64.Type}}),
#"Change to T/F" = Table.TransformColumnTypes(#"Change to INT",{{"Ordered Recently", type logical}})
in
#"Change to T/F"
The result looks like this:
Customer Name Ordered Recently
Customer 1 True
Customer 2 False
Customer 3 False
Customer 4 True
Customer 5 True
I added two measures:
Count Total = COUNTROWS(Customers)
Count Recent = CALCULATE([Count Total], filter(Customers, Customers[Ordered Recently]))
If I put both measures in a bar chart and highlight the "Count Recent" measure, I'd expect it to know to filter other visuals based on the FILTER statement present in the measure, but that doesn't happen. Selecing this value doesn't impact anything else on my page (including just a count of rows).
The goal is to allow people to select a measure that counts rows and then to see the makeup of the data in those rows (select a count of late projects and filter other visuals to describe those late projects).
Is this possible or am I doing something wrong?
EXAMPLE:
Here's what it looks like now, with nothing selected:
When I select the black bar (the "Ordered Recently" measure), nothing changes right now - but here's what I want to happen (actually achieved with a slicer off screen on the T/F field):
I understand if my measure is a SUM of an integer field, it includes every row in the calculation - even when the row value is zero - and there's no way to filter my dataset based on that. However, in this case, my measure is actually using a FILTER on the dataset so that it only counts rows with a certain criteria set - given that, it should be able to filter the requested table, and then flow that filter through the rest of my dataset (the same way it would if I selected a bar from a chart where I had used that same field as the series - exactly how it works when I do this:
PBIX file to download as an example
No, I don't believe it's possible to make a measure value cross-filter other visuals based on filters within the measure definition.
You can, however, click on i.e. row header Customer 3 and it should cross-filter the other visuals to only include that customer. Any table column you set for the rows or columns of a matrix visual should behave this way.
Here's a hacky workaround:
Create a measure that shows the right values when you use the column you want to use as a filter as the Legend or Axis (like in your last image). For example, in this case, you could do this:
Total Customers =
VAR TF = SELECTEDVALUE ( Customers[Ordered Recently] )
RETURN
COUNTROWS (
FILTER (
ALLSELECTED ( Customers ),
IF ( TF, TF, TF || Customers[Ordered Recently] )
)
)
This behaves how you want, but isn't labeled as you want. To achieve that create a calculated column with the labels you want. For example,
Label = IF(Customers[Ordered Recently], "Ordered Recently", "Total Customers")
Then take Ordered Recently off the axis and put the Label column in the Legend box to get this:
Your Filter argument is really Filter(All(Customers, Customers[Ordered Recently])
You remove all filters on the Customer Table, and then specify Ordered Recently Column as the filter.
Try
[MeasureName] =Calculate([Count Total], All(Customer), Values(Customer[Recently Ordered]), Customer[Recently Ordered] = “True”)

How to JOIN summarized data from two queries into new table in DAX Power BI

I have 2 queries:
Premium:
and Losses:
How can I simply summarize data from Premium query and LEFT JOIN it to summarized data in Losses query using DAX?
In SQL it would be like that:
declare #PremiumTable table (PolicyNumber varchar(50), Premium money)
insert into #PremiumTable values
('Pol1', 100),
('Pol1', 50),
('Pol2', 300),
('Pol3', 500),
('Pol3', 200),
('Pol4',400)
declare #LossesTable table (PolicyNumber varchar(50), Losses money)
insert into #LossesTable values ('Pol1',115),
('Pol1',25),
('Pol2',0),
('Pol3',110),
('Pol3',75)
select p.PolicyNumber,
sum(p.Premium) as Premium,
sum(l.Losses)as Losses
from #PremiumTable p
LEFT JOIN #LossesTable l on p.PolicyNumber = l.PolicyNumber
group by p.PolicyNumber
Result:
I tried using NATURALLEFTOUTERJOIN but it gives me an error:
*An incompatible join column, (''[PolicyNumber]) was detected. 'NATURALLEFTOUTERJOIN' doesn't support joins by using columns with different data types or lineage.*
MyTable =
VAR Premium =
SELECTCOLUMNS(
fact_Premium,
"PolicyNumber",fact_Premium[PolicyNumber],
"Premium", fact_Premium[Premium]
)
VAR Losses =
SELECTCOLUMNS(
fact_Losses,
"PolicyNumber", fact_Losses[PolicyNumber],
"Losses", fact_Losses[PaymentAmount]
)
VAR Result = NATURALLEFTOUTERJOIN(Premium,Losses)
RETURN Result
There are a few interdependent "bugs" or limitations around the use of variables (VAR) and NATURALLEFTOUTERJOIN which makes this a weird case to debug.
Some notable limitations are:
VAR:
Columns in table variables cannot be referenced via
TableName[ColumnName] syntax.
NATURALLEFTOUTERJOIN:
Either:
The relationship between both tables has to be defined before the
join is applied AND the names of the columns that define the
relationship need to be different.
Or:
In order to join two columns with the same name and no relationships,
it is necessary that these columns to have a data lineage.
(I'm a bit confused because the link mentioned do not have a data lineage; while official documentation said only columns from the same source table (have the same lineage) are joined on.)
Come back to this case.
SUMMARIZE should be used instead of SELECTCOLUMNS to obtain summary tables for Premium and Losses, i.e.:
Premium =
SUMMARIZE(
fact_Premium,
fact_Premium[PolicyNumber],
"Premium", SUM(fact_Premium[Premium])
)
Losses =
SUMMARIZE(
fact_Losses,
fact_Losses[PolicyNumber],
"Losses", SUM(fact_Losses[Losses])
)
When we apply NATURALLEFTOUTERJOIN to the above two tables, it'll return error No common join columns detected because of they have no relationship established.
To resolve this, we can make use of TREATAS as suggested in this blog post. But to use TREATAS, we have to reference the column names in Premium and Losses table, so we can't use VAR to declare them, but have to actually instantiate them.
To conclude, the solution would be:
Create calculate tables for Premium and Losses as mentioned above.
Use TREATAS to mimic a data lineage and join Premium table with Losses_TreatAs instead.
MyTable =
VAR Losses_TreatAs = TREATAS(Losses, Premium[PolicyNumber], Losses[Losses])
RETURN NATURALLEFTOUTERJOIN(Premium, Losses_TreatAs)
Results:
There's a sleazy hack that can successfully work around this awful limitation (what were the product designers thinking?).
If you add zeros (e.g. + 0) or concatenate an empty string (e.g. & "") to each join column within SELECTCOLUMNS, it breaks out of the data lineage straitjacket and runs the NATURALLEFTOUTERJOIN just using column names.
You can use this in a Measure to run dynamic logic (based on the query context from filters etc), not just while creating a calculated table.
Here's an tweaked version of your code:
MyTable =
VAR Premium =
SELECTCOLUMNS(
fact_Premium,
"PolicyNumber",fact_Premium[PolicyNumber] & "",
"Premium", fact_Premium[Premium]
)
VAR Losses =
SELECTCOLUMNS(
fact_Losses,
"PolicyNumber", fact_Losses[PolicyNumber] & "",
"Losses", fact_Losses[PaymentAmount]
)
VAR Result = NATURALLEFTOUTERJOIN(Premium,Losses)
RETURN Result
H/T to example #7 on this page, which shows this in code (without really explaining it).
https://www.sqlbi.com/articles/from-sql-to-dax-joining-tables/#code7
Hello I suggest you this way:
in PowerQuery, built up a table with policyNumber like that:
Duplicate Premium table, and remove the premium column on the duplicate. Call it PremiumPol
Duplicate the Losses table, and remove the losses column on duplicate. Call it LossesPol
Then use the button Append Query, to Append PremiumPol and LossesPol. Call it policynumber
Last remove duplicate from the appended tables
Then click on close and Apply
Check that your model is like that:
Then, to add losses and premium on a policy base is trivial, go on and select a table visual and these fields:
the result is like this:
Hope that helps!