I am trying to create dynamic Time Intelligence in SSAS Tabular similar to traditional OLAP Time Intel.
Additionally, I need Time Intelligence that can handle two sets of date hierarchies. For example, a Transmission Date and an Activity Date.
For example, I am trying to create a simple year-to-date sum of gross sales given that the user has selected two filters in an Excel pivot table. We are talking about all dates of transmission but only from the point of view of a single activity date. That is, I want to view 2016 total sales as if it were today, but also as if it were last month (i.e. as of a month ago, what did sales look like?).
An additional caveat is that I need two special calendars: a radio broadcast calendar for the transmission period and a traditional gregorian for the activity period.
I have started here:
YTD :=
IF (HASONEVALUE ( Dates[Years-Bcast] ),
CALCULATE (
SUM ( Sales[Sales Amount] ),
FILTER (
ALL( Dates ),Dates[Years-Bcast] = VALUES ( Dates[Years-Bcast] )
&& Dates[DatesKey] <= MAX ( Dates[DatesKey] )
)
),
BLANK ()
)
The problem I assume is my filter; I really want the last FILTER clause to be:
&& Dates[ActivityDateKey] <= MAX ( Dates[DatesKey] )
The activity date would be a user-defined report filter. It seems I need 2 filters. The first filter is filtering out only the applicable transmission dates I need, so then my activity date filter is pointless.
Any help would be greatly appreciated.
this might be what you're looking for..
KEEPFILTERS - https://msdn.microsoft.com/en-us/library/hh758426.aspx
Related
I have Cartons table, which contains two datatime columns - entering warehouse date and exiting warehouse date. For my report i need to calculate table which shows how many cartons are in the warehouse at the end of the each day. My idea was get number of cartons for each date which have entering date lower than current date and exiting date higher than current date. So i need to translate following sql into dax:
SELECT d.date, COUNT(c.Id) AS 'Count of cartons' FROM #dim d
INNER JOIN Inventory.Cartons c on d.date between c.EnteringWarehouseTime and c.ExitingWarehouseTime
GROUP BY d.date
ORDER By d.date
Where dim is table with all dates.
But all joins in dax can be performed only using relations. I can only make cross join of these tables and filter result, but this operation would take to much time. Do i have another options for this?
Actually you can simulate a relationship with dax. However, if I understand correctly your questions and the datamodell, you want to query all cartons that are still in the warehouse at a given time, right? For each day in the Date table you can calculate that how many rows in the Carton table are by filtering it by the currently iterated Day. So this formula calculates:
For each day in the date table - VALUES('Date') -, will calculate how many rows in the Cartons table present used some filtering - COUNTROWS('Cartons') -. And the filtering works like this: On the current value of the Day - think as a foreach in C# - it will check that how many rows are in the Cartons table present where it's Exiting date is higher or equal than the current Date's value in the iteration, and Enter date is lower the the current date, or it is BLANK() - so still in the warehouse.
CALCULATETABLE(
ADDCOLUMNS(
VALUES('Date'),
"Cartons",
CALCULATE(
COUNTROWS('Cartons'),
FILTER(
'Cartons',
'Cartons'[EnteringWarehouseTime] <= 'Date'[Date]
),
FILTER(
'Cartons',
OR('Cartons'[ExitingWarehouseTime] >= 'Date'[Date],ISBLANK('Cartons'[ExitingWarehouseTime])
)
)
)
)
This is very similar to the "Open orders" pattern. Check out daxpatterns.com
If you want to simulate a relationship you can always use the COUNTROWS() > 0 pattern as a filter.
Like if you want to do a SUM(Value) on your main table, but only for those rows that are present in the Referenced table - without relationship:
CALCULATE(
SUM('MainTable'[Value]),
FILTER(
'MainTable',
CALCULATE(
COUNTROWS('ReferencedTable'),
'ReferencedTable'[PK] = 'MainTable'[FK]
) > 0
)
)
I am struggling with a DAX pattern to allow me to plot an average duration value on a chart.
Here is the problem: My dataset has a field called dtOpened which is a date value describing when something started, and I want to be able to calculate the duration in days since that date.
I then want to be able to create an average duration since that date over a time period.
It is very easy to do when thinking about the value as it is now, but I want to be able to show a chart that describes what that average value would have been over various time periods on the x-axis (month/quarter/year).
The problem that I am facing is that if I create a calculated column to find the current age (NOW() - [dtOpened]), then it always uses the NOW() function - which is no use for historic time spans. Maybe I need a Measure for this, rather than a calculated column, but I cannot work out how to do it.
I have thought about using LASTDATE (rather than NOW) to work out what the last date would be in the filter context of any single month/quarter/year, but if the current month is only half way through, then it would probably need to consider today's date as the value from which to subtract the dtOpened value.
I would appreciate any help or pointers that you can give me!
It looks like you have a table (let's call it Cases) storing your cases with one record per case with fields like the following:
casename, dtOpened, OpenClosedFlag
You should create a date table with on record per day spanning your date range. The date table will have a month ending date field identifying the last day of the month (same for quarter & year). But this will be a disconnected date table. Don't create a relationship between the Date on the Date table and your case open date.
Then use iterative averagex to average the date differences.
Average Duration (days) :=
CALCULATE (
AVERAGEX ( Cases, MAX ( DateTable[Month Ending] ) - Cases[dtopened] ),
FILTER ( Cases, Cases[OpenClosedFlag] = "Open" ),
FILTER ( Cases, Cases[dtopened] <= MAX ( DateTable[Month Ending] ) )
)
Once you plot the measure against your Month you should see the average values represented correctly. You can do something similar for quarter & year.
You're a genius, Rory; Thanks.
In my example, I had a dtClosed field rather than an Opened/Closed flag, so there was one extra piece of filtering to do to test if the Case was closed at that point in time. So my measure ended up looking like this:
Average Duration:=CALCULATE(
AVERAGEX(CasesOnly, MAX(DT[LastDateM]) - CasesOnly[Owner Opened dtOnly]),
FILTER(CasesOnly, OR(ISBLANK(CasesOnly[Owner Resolution dtOnly]),
CasesOnly[Owner Resolution dtOnly] > MAX(DT[LastDateM]))),
FILTER(CasesOnly, CasesOnly[Owner Opened dtOnly] <= MAX(DT[LastDateM]))
)
And to get the chart, I plotted the DT[Date] field on the x-axis.
Thanks very much again.
I have a couple of tables in PowerPivot:
A Stock table - WKRelStrength whose fields are:
Ticker, Date, StockvsMarket% (values are percentages), RS+- (values can be 0 or 1)
A Calendar Table - Cal with a Date field.
There is a many to one relationship between the tables.
I am trying to aggregate RS+-against each row for dates between 3 months ago to the date for that row - i.e a 3 month to date sum. I have tried numerous calculations but the best I can return is an circular reference error. Here is my formula:
=calculate(sum([RS+-]),DATESINPERIOD(Cal[Date],LASTDATE(Cal[Date]),-3,Month))
Here is the xlsx file.
I couldn't download the file but what you are after is what Rob Collie calls the 'Greatest Formula in the World' (GFITW). This is untested but try:
= CALCULATE (
SUM ( WKRelStrength[RS+-] ),
FILTER (
ALL ( Cal ),
Cal[Date] <= MAX ( Cal[Date] )
&& Cal[Date]
>= MAX ( Cal[Date] ) - 90
) )
Note, this will give you the previous 90 days which is approx 3 months, getting exactly the prior 3 calendar months may be possible but arguably is less optimal as you are going to be comparing slightly different lengths of time (personal choice I guess).
Also, this will behave 'strangely' if you have a total in that it will use the last date in your selection.
First of all, the formula that you are using is designed to work as a Measure. This may not work well for a Calculated Column. Secondly, it is better to do such aggregations as a Measure level, than at individual records.
Then again, I do not fully understand your situation, but if it is absolutely important for you to do this at a Record level, you may want to use the "Earlier" Function.
If you want to filter a function, based on a value in the correspontinf row, you just have to wrap your Column name with the Earlier Function. Try changing the LastDate to Earlier in your formula.
I'm building a PowerPivot/AS data model and I need to convert a date to the appropriate sprint. A sprint is defined as a span of dates (i.e. Sprint N = date range from Date A to Date B). Ideally, I can add this new value as a field in my Date hierarchy. How can I write a DAX formula that will take a date and output the appropriate sprint?
To make things more complicated, in an ideal world different teams can have different dates for a sprint so it would be nice to take the teamId as input and use that to help compute the appropriate sprint name for a given date. NOTE I do have the team/sprint name/sprint start & end dates available for querying
I made a table that looks like the image below and used it with a date dimension table.
I am not sure how you could dynamically calculate the sprint based upon a parameter to indicate the team. This formula would work if you make one column per team in your date table in PowerPivot/Tabular AS.
Team1 Sprint=CALCULATE(
LASTNONBLANK(TeamSprints[SprintName] , 1 ),
FILTER(
TeamSprints,
TeamSprints[SprintName] = CALCULATE(
LASTNONBLANK( TeamSprints[SprintName],1 ),
FILTER(
TeamSprints,
TeamSprints[TeamID] = 1 &&
TeamSprints[StartDT] <= Date[DateKey] && TeamSprints[EndDT] >=Date[DateKey]
)
) &&
TeamSprints[TeamID] = 1
)
)
I figured this out based on Javier Guillen's blog post
I have a cube with a typical snapshot structure and daily granularity (like inventory quantities). I would like to be able to remove some of the granular data from this cube, because we have something like 270,000,000 rows of source data, cube processing is slow, and there isn't a meaningful difference from one data point to the next, at the day level.
However, users want a graduated level of detail - daily detail for the recent past, then monthly or quarterly for older periods. Doing that would help the situation BUT - they also want charts that "appear" to show data for each data point and not have "holes" between one data point and the next.
So here's the question: if I have a cube with a snapshot fact table, and the table has daily values for the most recent 30 days, then monthly values for 6 months, then quarterly values for two years prior, is there any sane way to make output from the cube "spoof" the gaps, by repeating the last snapshot value for each "empty" day? In other words, if I deliver a chart over the whole time period, I want it to have plateaus that repeat the last non empty value across each gap in the data, but without incurring the storage penalty of keeping all those values.
You could in the cube use a MDX calculated measure for day level, which looks up the last available data point.
Not sure if that idea helps, but that's where I would start looking.
I am close on this. Came up with the following type of recursive expression, which seems to work (mostly). Tried to substitute in the ClosingPeriod() function to tidy it up, but that bit doesn't work:
/* Works! */
with member Measures.lastEstatementsCount as
iif(
isleaf( [Date].[Calendar].currentmember ),
iif(
isempty([Measures].[_Add E Statements Count]),
( [Date].[Calendar].prevmember, Measures.[lastEstatementsCount] ),
Measures.[_Add E Statements Count]
),
(
( tail( descendants( [Date].[Calendar].currentmember ) ) ).item(0),
Measures.[lastEstatementsCount]
)
)
select
Measures.lastEstatementsCount on columns,
[Date].[Calendar].[Month Name] on rows
from [EngagedMember];
/* Substituting ClosingPeriod() in the recursion doesn't for some reason */
with member Measures.lastEstatementsCount as
iif(
isleaf( [Date].[Calendar].currentmember ),
iif(
isempty([Measures].[_Add E Statements Count]),
( [Date].[Calendar].prevmember, Measures.[lastEstatementsCount] ),
Measures.[_Add E Statements Count]
),
(
ClosingPeriod( [Date].[Calendar].[Date], [Date].[Calendar].currentmember ),
Measures.[lastEstatementsCount]
)
)
select
Measures.lastEstatementsCount on columns,
[Date].[Calendar].[Month Name] on rows
from [EngagedMember];