I have a metric I need to replicate in DAX for PowerBI and I am not quite sure how to do it.
The basics are this:
Fact Table: Opportunity
Dimensions: Created Date, Closed Date
The metric goes like this, I will just give an example, because I really dont know how to explain it.
SUM OF:
Created in FEB and Closed Date in FEB, MAR, APR
Created in MAR and Closed Date in MAR, APR
Created in APR and Closed in APR
This would happen for each month in the table/matrix.
Seems like I would need some variables something like
Measure =
VAR Month1 = SUM(ClosedOpps) where ClosedDate between CurrentMonth and CurrentMonth + 2
VAR Month2 = SUM(CLosedOpps) where ClosedDate betwwen CurrentMonth + 1 and CurrentMonth + 2
VAR Month3 = SUM(ClosedOpps) where ClosedDate = CurrentMonth + 2
Return Month1 + Month2 + Month3
My understanding is, the Closed Date filter would be the Table/Matrix Visual when I drag the column MonthYear into the visual
EDIT:
Here is a simplified replica of what they are doing in Excel
So The data on the left is the fact table. You can see when the Opps are created, when they are closed. I added in the Created MonthYear and the Closed MonthYear. The Pivot is what they have now in Excel. Dates across the top (Columns) are Created YearMonth, Dates for the Rows are Closed YearMonth.
I need to be able to SUM the numbers inside the of I3:K5 which total 5500 in the example.
UPDATE:
So I have added in a suggested Date Dimension table, Duplicated it (One for Open Date, one for Closed Date) I added a column DateDIM_KEY to each which is just a numerical index. The fact table has these keys, and they are loaded off of the same date range (2013 to 2030). The column ActualValue in the fact table is the column we would SUM.
Here is the updated Fact table sample. I pulled the DateDIM_KEY values directly from the date dimension for those dates.
You need a good date dimension. And you need to have it roleplaying for OpenDate and CloseDate. There are many good date dimensions out there. I like mine.
Assuming that you're putting 'OpenDate'[Month] on an axis label.
Opportunity Value = SUM ( 'Opportunity'[Value] )
MyMeasure iterator =
// start of the month on the current row of a pivot/axis label of a chart
VAR CurrentMonthStart = MIN ( 'OpenDate'[Date] )
// End of the month 2 months out
VAR ThreeMonthsOutEnd = EOMONTH ( CurrentMonthStart, 2 )
// This represents one row per month. You could also use a MonthAndYear type field.
// We will walk through the three open months we care about, and in each will sum
// the value for the opportunities opened in that month, with additional filters.
VAR NextThreeOpenMonths =
CALCULATETABLE (
VALUES ( 'OpenDate'[MonthIndex] ),
ALL ( 'OpenDate' ),
DATESBETWEEN ( 'OpenDate'[Date], CurrentMonthStart, ThreeMonthsOutEnd )
)
RETURN
// Iterate each OpenMonth
SUMX (
NextThreeOpenMonths,
// On each step of the iteration, grab the start of the currently iterated month
VAR IterMonthStart = CALCULATE ( MIN ( 'OpenDate'[Date] ) )
RETURN
CALCULATE (
[Opportunity Value],
// There is date context from visuals we want to ignore:
ALLEXCEPT ( 'OpenDate', 'OpenDate'[MonthIndex] ),
// filter CloseDate to be between the start of the currently iterated
// open month and the originally calculated ThreeMonthsOutEnd. The latter
// is static within the scope of the iteration.
DATESBETWEEN ( 'CloseDate'[Date], IterMonthStart, ThreeMonthsOutEnd )
)
)
Also, while writing the previous iterative approach, I realized we could do the work in a single setfilter:
MyMeasure set =
// MonthIndex is in my date dimension - super useful for arithmetic on dates.
// Read the readme.
VAR C = SELECTEDVALUE ( 'OpenDate'[MonthIndex] ) // want a short name below
// Table literal syntax - two column table, where each parenthesized expression
// forms a row. If it were much more, I'd do something clever with generate, but
// six cases are easy to write by hand.
VAR MonthFilters = {
(C, C),
(C, C+1),
(C, C+2),
(C+1, C+1),
(C+1, C+2),
(C+2, C+2)
}
RETURN
CALCULATE (
[Opportunity Value],
TREATAS ( MonthFilters, 'OpenDate'[MonthIndex], 'CloseDate'[MonthIndex] )
)
I like the latter a lot better, but didn't think of it until after writing the iterative version, so I'm leaving both. Set-based should be better performing.
Edit: some screengrabs I forgot:
Here's the relationship diagram for roleplaying date dim:
And here's the visual in action with both measures:
Best thing to do here is to add a custom column (under edit querys) with the date diff per month. Now you can filter after the column LeadTimeInMonth for you scenarios. If you drag and drop your fields into the visual you can filter by this column.
Date.Month([ClosedDAte])-Date.Month([OpenDate])
I am not sure what you really want to evaluate but if you need need exactly ClosedDate between CurrentMonth and CurrentMonth + 2 you can first evaluate the month from the ClosedDate then the month of today and filter after the result.
Related
I have a table where where I want to create last 12 months flag column from the latest date available in each country. I have tried many Dax formula without success.
My table looks like below:
Here Y indicates the dates falls under last twelve months.
Please help me to find this flag.
You can create a calculated column to validate the date falls within the last 12 months, for each country. First calculate the maxDate for each country, then ensure the date is greater than the MaxDate with an if statement
Last 12 Months =
VAR MaxDate = CALCULATE (
MAX ( Country[Date] ),
ALLEXCEPT ( 'Country', 'Country'[Country] )
)
RETURN
IF (
Country[Date]> DATE(YEAR(MaxDate)-1, Month(MaxDate), Day(MaxDate)) ,1,0
)
This will then give you a filterable column to work from
I need to show how many active contracts we have open for each month in the last 6 months. I am trying to figure out a way to display this. Here is my table
Machine Enrollment# StartDate EndDate
A 1 1/2/2016 6/18/2019
B 2 12/15/2012 5/12/2034
C 3 3/25/2019 4/25/2021
D 4 1/7/2000 7/15/2019
A 5 10/1/2019 10/1/2025
I have thousands of rows. I want to be able to show a rolling 6 month visual for how many machines are under contract. So in this small example it would look like this
Apr-19 June-19 Jul-19 Aug-19 Sep-19 Oct-19
4 4 3 2 2 3
Where do I even begin in creating this? In the past, we have just looked at the numbers for the current month and tacked those results onto the end of a static table and deleted the column from over 6 months ago. I have been assigned to automate this report in Power BI. I am guessing I need to create a column/measure that looks at the EndDate and compares it to the filtered Date in the visual (ie: Aug-19) and determines if the contract was open at that time. But I do not know. Any help is much appreciated. Thanks in advance!
I think I found a solution for what you are looking for. You may find a sample pbix file here.
1. Create a calendar table
A calendar table is required to filter/slice the time periods. The calendar table needs to have a unique Date column, and optional columns such as Year, Quarter, and Month, depending on what units of period you need in the analysis.
A calendar table can be most easily created as a DAX calculated table. Here is an example of a minimal calendar table required in this use case.
Calendar =
ADDCOLUMNS(
CALENDAR( MIN( Contracts[StartDate] ), MAX( Contracts[EndDate] ) ),
"Year Month", FORMAT( [Date], "mmm-yy" ),
"Year Month Number", YEAR( [Date] ) * 100 + MONTH( [Date] )
)
2. Create a measure to calculate number of open contracts
Every numbers calculated and shown in reports need to be defined as measures.
Let's think about the number of May-19. The current filter context includes all 31 dates in the Calendar table between 2019-05-01 and 2019-05-31. In this case, how can we think of an open contract? If the contract starts after 2019-05-31, it is not open. If the contract ends before 2019-05-01, it is not open as well. Therefore the open contract meets this condition.
Starts on or before 2019-05-31 and
Ends on or after 2019-05-01
Below is the measure definition to count the number of contracts based on this condition.
# Open Contracts =
VAR MinDate = MIN( 'Calendar'[Date] )
VAR MaxDate = MAX( 'Calendar'[Date] )
RETURN COUNTROWS(
FILTER(
Contracts,
Contracts[StartDate] <= MaxDate
&& Contracts[EndDate] >= MinDate
)
)
3. Add dynamic filter for last 6 months
If I was understanding correctly, the requirement is to show monthly number of last 6 calendar months, excluding this month. I could not find a straightforward way for this. My solution may contain a bit of hacky scent.
Power BI does not have built-in filter support based on calendar months relative to now. We need to build a custom logic to achieve this. I did it by creating a measure that indicates whether current filter context is within the desired period. This measure is a flag that returns 1 if the filter context is a single calendar month which is included in the last 6 calendar months, or returns BLANK otherwise.
__Last6MonthFlag =
VAR YearMonths = CALCULATETABLE(
VALUES( 'Calendar'[Year Month] ),
REMOVEFILTERS( 'Calendar'[Year Month] ),
'Calendar'[Date] > EOMONTH( TODAY(), -7 )
&& 'Calendar'[Date] <= EOMONTH( TODAY(), -1 )
)
RETURN IF(
HASONEVALUE( 'Calendar'[Year Month] )
&& SELECTEDVALUE( 'Calendar'[Year Month] ) IN YearMonths,
1
)
Then I used this measure in the visual filter like this.
You need to do below activities to achieve your requirement.
Define a calendar table holding all the dates for your report. Define a calculated column for Month-Year. Month-Year = FORMAT('CalendarTable'[Date], "MM-YYYY")
You can define a calculated measure, which will return 1 if the end date of the contract is < 6 months from current date (you can use TODAY() function). This function will help in rolling calculation based on current date. Otherwise, this calculated measure will return NULL and SUM them.
You can drag the month-Year calculated column, defined in step no. 1, to the column axis. You can drag the calculated measure, defined in step no.2, to the values section. PowerBI control by default filters out the NULL values. So, when you use the calculated measure defined in step no. 2, you will get values only for the last 6 months. As the calculation is defined based on TODAY(), it will be a running calculation.
Story:
Basically I'm trying to showcase the month to date compared to the parallel month along with the delta.
Usually this will only be used for the current month. I was able to add future dates but the values for month to date is repeated for all the days in the future
Objective:
I would like the value to be 0 instead of the last value being repeated for the entire future dates
Essentially I would like the following code for my measure but its not working:
_Join MTD =
IF(
TODAY()<Current Row date,
0,
TOTALMTD(SUM('Fact Table'[Join Count]),'Date Table'[Date])
)
Measures have no concept of a "current row". Measures are only affected by filter context. This can be confusing at first, because a table visual or a matrix visual has row labels, but these things are contributing filter context. The only place you will find row context is when adding a calculated column to a data table or within an iterator function.
You can probably do something like what I show below, but if you need any more help you'll need to share a sample of your data model (tables, columns, a few sample rows from each, relationships among tables) as well as the visual you're building.
_Join MTD =
IF(
TODAY () < MIN ( 'Date Table'[Date] ), // here we find the smallest day in filter
// context with MIN. If there is only one day
// in context, well then that is the min
0,
TOTALMTD ( SUM ( 'Fact Table'[Join Count] ), 'Date Table'[Date] )
)
It's a common idiom in DAX to take the MAX or MIN of a column when you want a "currently selected" value, though there are also more selective functions, such as SELECTEDVALUE if you want to guarantee that exactly one value is in filter context.
Edit: Per comments, the goal is to compare to yesterday, not today. We can simply take the measure above and modify its predicate as below:
( TODAY () - 1 ) < MIN ( 'Date Table'[Date] )
Arithmetic operators do reasonable things with date and time types in DAX. Also sometimes useful is that the DATE function deals gracefully with overflow and underflow, per the examples below:
DATE ( 2018, 1, 366 ) // => 2019-01-01
DATE ( 2018, 0, 1 ) // => 2017-12-01
DATE ( 2019, 2, 31 ) // => 2019-03-03
DATE ( 2019, 3, 0 ) // => 2019-02-28
So, if you must, you can abuse this function for date shifting as well, though it's usually a last resort.
I have a summarize table that is summed by the Date and Building_Name. I am trying to figure out how to add an increase/ decrease column like my table below. I want to show if the 'total unsigned' has increased from day to day for each building.
I cannot get a formula that will take the previous days total for one building - current days # of total unsigned. Trying to get the forth column for my report.
I can get it to work if I am just showing day over day change if I am not also trying to add the Building_name to the table.
Unsigned Prev Day =
VAR CurrentDay = SELECTEDVALUE(SummarizeTable[Day Number])
VAR CurrentMonth = SELECTEDVALUE(SummarizeTable[Month Number])
VAR MaxDayNumber = CALCULATE(MAXA(SummarizeTable[Day Number]))
Return SUMX(
FILTER(ALL(SummarizeTable),
IF( CurrentDay = 1,
SummarizeTable[Day Number] = MaxDayNumber && SummarizeTable[Month Number]= CurrentMonth-1,
SummarizeTable[Day Number] = CurrentDay -1)),
[Total Unsigned])
Edit:
Thank you for the help, you definitely put me on the right track. This is the formula I ended up using. Thank you again for the help!
Unsigned Prev Day =
VAR MostRecentDate = MAX ( 'SummarizeTable'[Date] )
RETURN
CALCULATE (
[Total Unsigned],
ALL ( 'SummarizeTable'[Date], 'SummarizeTable'[Day Number], 'SummarizeTable'[Month Number] ),
'SummarizeTable'[Date] = MostRecentDate - 1
)
This assumes that you have or can make a column, 'SummarizeTable'[Date]. If you already have month and day, this should be trivial. This solution takes advantage of the fact that DAX has well-behaved arithmetic on dates.
Additionally, you should look at building a date dimension, rather than doing all of this out of a single table. It will ultimately make your life a lot easier. There are a bunch of good date dimensions out there, but I'm partial to mine.
EDIT: Per discussion in comments the goal is to add this as a calculated column to a data table. The definition above is intended to be used as a measure.
# Increase/ Decrease =
CurrentRowDate = 'SummarizeTable'[Date]
RETURN
CALCULATE (
SUM ( 'SummarizeTable'[Total Unsigned] ),
ALLEXCEPT ( 'SummarizeTable'[Building] ),
'SummarizeTable'[Date] = CurrentRowDate - 1
)
This will add a column to 'SummarizeTable' that has the sum of [Total Unsigned] for the same value of [Building] as is on the current row and with a date 1 less than that on the current row.
I have the following Data :
I want to achieve a solution where, when I filter year, it returns me the average of Goodwill of that year and the previous year.
So for my year filter 2017: Average of Goodwill in 2017,2016
year filter 2016: Average of Goodwill in 2016,2015
.... and so on
The year is in General format (NOT Date format) ..
Expected OUTPUT Values:
Not sure what you have tried (or how familiar you are with Power BI/DAX), but you will most likely need to use a combination of DIVIDE, CALCULATE, and ALL. The DIVIDE function isn't super necessary, but it is a great habit to get into as it catches errors. Combining the CALCULATE and ALL will allow you to take the sum for the selected year and the prior year.
What I would do is this:
Goodwill - 2yr Avg =
VAR MaxSelectedYear = MAX([Year])
VAR PriorYear = MaxSelectedYear - 1
VAR MinYearInData = MINX(ALL(Data), [Year])
RETURN
DIVIDE(
CALCULATE(SUM([Goodwill]), FILTER(ALL(Data[Year]), [Year] = MaxSelectedYear))
+
CALCULATE(SUM([Goodwill]), FILTER(ALL(Data[Year]), [Year] = PriorYear))
,
IF(PriorYear < MinYearInData, 1, 2),
BLANK()
)
The IF statement at the end will catch when you are looking at the first year, so that the sum is only divided by 1 instead of 2. The sum will only be 1 year of data since when you filter the Data table to the prior year, there will be no data.
Maybe something like this?
My Average =
IF(HASONEVALUE(Data[Year]);
DIVIDE(
CALCULATE(SUM(Data[Goodwill]);FILTER(ALL(Data[Year]);Data[Year]>=SELECTEDVALUE(Data[Year])-1 && Data[Year]<=SELECTEDVALUE(Data[Year])))
;2);
BLANK()
)
HASONEVALUE, just to identify if my current scope only has 1 year selected for the calculation to be applied.
Than getting the value for the current year and previous year with FILTER and SELECTEDVALUE
I am hardcoding the division by two, but you can adjust it depending on your dataset and purpose.