I know this must be extremely simple, but every example I can find online only works within a single table. I've simplified my situation to these two tables:
I want to add a calculated column to the first table, showing the most recent value for that id. It also needs to work with text.
There are a variety of ways to do this kind of thing as I've explained before and all of the solutions there can be adjusted to work in this case.
Doing this as a calculated column and with a second table, you need to make sure you are using row context and filter context appropriately.
Here's are a couple different possibilities I think may work:
MostRecentValue =
MAXX ( TOPN ( 1, RELATEDTABLE ( Table2 ), Table2[date] ), Table2[value] )
In this one, RELATEDTABLE is doing the work of filtering Table2 to only the rows where id matches Table1.
MostRecentValue =
VAR PrevDate = CALCULATE ( MAX ( Table2[date] ) )
RETURN CALCULATE ( MAX ( Table2[value] ), Table2[date] = PrevDate )
The relationship is more subtle here. Wrapping the MAX in CALCULATE forces a context transition so that the row context (which includes id) is applied to Table2 as filter context.
Related
My data
Fact
iddimUser iddimtime
123 81200
124 84500
DimTime
iddimtime FullTime
81200 08:12:00.0000000
84500 08:45:00.0000000
Desired Table calculation
iddimUser iddimtime Time
123 81200 08:12:00.0000000
124 84500 08:45:00.0000000
I require to bring to the fact table a specific time from the time dimension base on one of the multiple relationships I have (I have several IdTimes in the fact table).
I tried this column calculation but getting an "A table of multiple values was supplied where a single value was expected" error
FullTime = TIME(
HOUR(CALCULATE( VALUES(DimTime[FullTime] ),
USERELATIONSHIP ( Fact[iddimtime], DimTime[iddimtime]))),
MINUTE(CALCULATE( VALUES(DimTime[FullTime] ),
USERELATIONSHIP ( Fact[iddimtime], DimTime[iddimtime]))),
SECOND(CALCULATE( VALUES(DimTime[FullTime] ),
USERELATIONSHIP ( Fact[IniciaProce], DimTime[iddimtime]))))
FullTime1 =
FORMAT(RELATED(DimTime[FullTime]),"hh:nn:ss")
This you can use as alternative to your measure and it will be much faster.
FullTime2 =
FORMAT(
LOOKUPVALUE(
DimTime[FullTime]
,DimTime[iddimtime]
,[iddimtime]
)
,"hh:nn:ss"
)
Why do you use the userelationship if there is only one active relationship between fact and dim tables ? All you need is the related function to access the related row in the dim table:
Note:
Ensure that The [iddimtime] column is the one who creates the relationship between both tables.
Related() is an iterator. Never use it with a calculate involving USERELATIONSHIP() in a calculated field.
RELATED() is used to access the column values from many side to one-side. Conversely, RELATEDTABLE() is used to access columns from one side to many side.
Please test this, and let me know if It solves your problem.
FullTime =
TIME ( HOUR ( RELATED ( DimTime[FullTime] ) ), MINUTE ( RELATED ( DimTime[FullTime] ) ), SECOND ( RELATED ( DimTime[FullTime] ) ) )
What is the difference between CALCULATE(m, x=red) and CALCULATE(m, KEEPFILTERS(x=red))
Apparently they are not the same. I found docs and explanation but I still do not get it.
https://learn.microsoft.com/en-us/dax/keepfilters-function-dax
https://dax.guide/keepfilters/
Your first measure, without KEEPFILTERS overrides all other filters applied to field x.
The second measure, using KEEPFILTERS maintains the filter context on field x, and applies the new filter context as a subset of existing filters (or blank, if no overlap of filter contexts).
Here's a simple example PBIX file to demonstrate - play with the colour slicer, and see the difference in the two measures: https://pwrbi.com/so_57850298/
This SQLBI.com article explains it well.
It is helpful to understand a bit more about how simple predicates in CALCULATE are evaluated. The following two expressions are equivalent; in fact, the first is just syntactic sugar for the second - the former is rewritten to the latter behind the scenes:
CALCULATE ( [m], 'T'[Col] = "Red" )
and
CALCULATE (
[m],
FILTER (
ALL ( 'T'[Col] ),
'T'[Col] = "Red"
)
)
FILTER is an iterator that takes a table as its first argument and a predicate to be evaluated in row context as its second argument. It removes any rows from the input table where the predicate is false.
Thus, CALCULATE manipulation of filter context is actually almost entirely manipulations of tables. If you're comfortable with the relational algebra, the tables in args2-N of CALCULATE are tables which are left semijoined to the table(s) being operated on in the expression in CALCULATE's arg1. These semijoins depend on relationships being defined in the data model.
So the pattern of FILTER ( ALL ( 'T'[Col] ), <predicate> ) ignores any external filter context on 'T'[Col] and replaces that with a new filter context that you are defining.
Now for KEEPFILTERS. I am not 100% positive that this is just syntactic sugar, but I believe it is. Either way, the two expressions below are semantically equivalent - they will always return the same values:
CALCULATE ( [M], KEEPFILTERS ( 'T'[Col] = "red" ) )
and
CALCULATE (
[M],
FILTER (
VALUES ( 'T'[Col] ), // this is the only difference from the first expansion
'T'[Col] = "red"
)
)
You can see that the KEEPFILTERS expansion is using VALUES instead of ALL. So, ALL returns all unique values from the named column, ignoring any filter context on that column (it also has other forms where it can operate on more than one column, but that is not relevant to this discussion). VALUES returns the unique values from the named column in the current filter context.
Another way to think of this is as follows. Assume that the value "red" does exist in 'T'[Col]. FILTER ( ALL ( 'T'[Col] ), 'T'[Col] = "red" ) will always return the 1-column, 1-row table of 'T'[Col] with the value "red". FILTER ( VALUES ( 'T'[Col] ), 'T'[Col] = "red" ) will always return a 1-column table, either with 0 or 1 row; if the external filter context includes 'T'[Col]="red", then it will return the 1-row table with 'T'[Col]="red", whereas if the external filter context does not include that value, it will return the empty table.
Again, the table output of the FILTER expressions above is treated as the right side table in a left semi-join.
Note, especially, that all of the above is based on single columns. You might get thrown for a loop if there are multiple columns contributing filter context. Here is an easy-to-understand example. We define two measures and put them into a table visual with 'DimDate'[Year] and 'DimDate'[Date].
Prior Date =
VAR CurrentDate = MAX ( 'DimDate'[Date] )
RETURN
CALCULATE (
MAX ( 'DimDate'[Date] ),
'DimDate'[Date] = CurrentDate - 1
)
Prior Day ALL DimDate =
VAR CurrentDate = MAX ( 'DimDate'[Date] )
RETURN
CALCULATE (
MAX ( 'DimDate'[Date] ),
ALL ( 'DimDate' ),
'DimDate'[Date] = CurrentDate - 1
)
And here's what they return in our table visual:
Arithmetic with dates is defined in DAX and <date> - 1 will always return the prior date. So CurrentDate - 1 on 2019-01-01 is 2018-12-31. But in our visual, we have filter context coming from both 'DimDate'[Year] and 'DimDate'[Date], so in the first measure, we're calculating MAX ( 'DimDate'[Date] ) in the filter context of 'DimDate'[Year]=2019 and 'DimDate'[Date]=2018-12-31 (the context manipulation in our CALCULATE). There are no rows in 'DimDate' that simultaneously match both of those conditions, so the first version returns blank. The second version clears all filter context coming from 'DimDate', so the only context remaining is what we explicitly apply with 'DimDate'[Date] = CurrentDate - 1.
Note that the example above would only return values for totals when we use KEEPFILTERS.
Prior Date KEEPFILTERS =
VAR CurrentDate = MAX ( 'DimDate'[Date] )
RETURN
CALCULATE (
MAX ( 'DimDate'[Date] ),
KEEPFILTERS ( 'DimDate'[Date] = CurrentDate - 1 )
)
This only works on totals, because at a detail level, there is no way for KEEPFILTERS ( 'DimDate'[Date] = CurrentDate - 1 to return any values. It's saying, essentially "find me a date that is one less than itself", which is obviously impossible. But at a grand total level, there are many dates in context, and so we're filtering a table of many contiguous dates. So our measure can return something for totals.
At the beginning I had this table
what I want is to divide the universe into 3 sections, so I do the following
i believe in column
UniqueRank =
RANKX (
inci;
FORMAT (inci[nro_casos]; "0000" ) & inci[region] & inci[site]
)
then I create two measures
ranking_total =
RANKX (
ALLSELECTED ( inci );
inci[UniqueRank];
MAX ( inci[UniqueRank] )
)
tirdh_case = IF(inci[ranking_total]<=COUNTROWS(ALLSELECTED(inci))*0.33;"3P";
IF(inci[ranking_total]<=COUNTROWS(ALLSELECTED(inci))*0.66;"2P";"1P"))
Then I would stay as follows. As you can see, filters of week and region can be applied and normal is divided into three parts, but I want to show it in a graph, and I want to put the tirdh_case as the axis, for this I create a new table called 'axis'
so I create the measure that intersects these two tables
suma_inci = CALCULATE (
SUM( inci[nro_casos] );
FILTER ( inci; [tirdh_case] IN VALUES ('axis'[indice]) )
)
As you can see in the image, the graph works perfectly, but I am inserting the 'site' column as a subcategory, so that when I click on each bar it shows me the sites that belong to that bar, but what happens is that all the sites are accumulate in the first bar ... how would you link the sites and categorize correctly?
This is logical because Measures are dynamically calculated based on your selection. So when you select your bar with the "P1", it needs to recalculate your splitting what is not possible because it is what you select. So if you want to go this level deeper, you need to make your measures a column so it is static divided.
Your column is than like:
tirdh_case =
var maxRank = MAX(inci[UniqueRank])
var splitNr = 3
var divider = maxRank/3
return CEILING((1 + maxRank - inci[UniqueRank])/divider;1) & "P"
You do not need an extra table now because you can use this column as your axis. I made it such that you can change the splitNr to your liking.
End result:
I have a problem where I need to figure out if a project has values outside it's start and finish date range.
Below is a simple relationship of dimension table containing start and finish dates of the projects. And a fact table containing time registration.
The table below has a column 'Outside Date Range' Which I'd like to have a true/false value. for example if Main2 Table contains a date Monday, May 13, 2018. The column should show false.
I tried something like
Outside Date Range = CALCULATE(SUM(Main2[Value]), FILTER(Main2, Main2[Time] < LOOKUPVALUE(Main[Start], Main[Project], ALL(Main2[Project]))))
But not really sure how to approach the relationship between the two tables properly.
The two approaches I would suggest are either a calculated column or a measure.
Calculated column:
Outside Date Range =
VAR rowsOutsideRange =
CALCULATE (
COUNTROWS ( Main2 ),
FILTER (
RELATEDTABLE ( Main2 ),
Main2[Time] < Main[Start]
|| Main2[Time] > Main[Finish]
)
)
RETURN
IF ( rowsOutsideRange > 0, TRUE (), FALSE () )
You were pretty close in your solution! Since you have a relationship between the two tables RELATEDTABLE will only return the related rows which removes the necessity of a LOOKUPVALUE(). Also, counting the rows is sufficient since we only want to know if any rows exist outside of the range, not how many.
You could also create a measure:
Outside Date Range Measure :=
VAR rowsOutsideRange =
CALCULATE (
COUNTROWS ( Main2 ),
FILTER (
Main2,
Main2[Time] < MIN ( Main[Start] )
|| Main2[Time] > MAX ( Main[Finish] )
)
)
RETURN
IF ( rowsOutsideRange > 0, TRUE (), FALSE () )
Which is pretty similar to the calculated column, the only this is we need to aggregate the start and finish dates. On its own this measure doesn't have any value, it needs to be sliced by a project to be correct. If you would really want to you could use a SUMX() type of construction to create an overall TRUE/FALSE statement which tells you if any of the project have rows outside their ranges but for your use case I don't see the benefit of that.
The choice between a calculated column and a measure is dependent on the legibility of the code and resource usage. A calculated measure uses more memory and a measure uses more CPU.
Looking at your case I would go for a calculated column, which seems the most simple and clear solution.
Hope that helps!
Jan
I'm working in Power BI.
I have a table with member card usage data called NonSameDayUses:
https://www.screencast.com/t/yeSjoqonZ
I have another table with member card add data called AddsOnly:
https://www.screencast.com/t/zlPBRWaDqC
The tables are related by the GUID_TranDate2 field. I am trying to add a column to NonSameDayUses that provides the date just before the use date (to calculate when the amount used was added to their card). I have tried a million things, but this is my current formula and I can't figure out what is wrong with it:
DateAdded =
MAXX (
FILTER (
AddsOnly,
AND (
AddsOnly[member_guid] = [member_guid],
AddsOnly[ValueAddDate] < [TransactionDate]
)
),
AddsOnly[TransactionDate]
)
Neither filter is working for me. If I try it with just the first argument (member_guid), I get blanks. If I try with the second (dates) I get the max date for the whole table with no filtering.
Any help would be sooooooooooo appreciated, as I am currently banging my head against the wall! :)
Try qualifying all the column names, it should work:
DateAdded =
MAXX(
FILTER(
AddsOnly
, AND(
AddsOnly[member_guid]
= NonSameDayUses[member_guid]
, AddsOnly[ValueAddDate]
< NonSameDayUses[TransactionDate]
)
)
, AddsOnly[TransactionDate]
)