Tableau - Creating Overlapping Date Bins - tableau-api

I have a report that will be updated Monday through Friday and want to display a single metric [Productivity %] across several different date [In_Date] "bins" i.e. a generated date dimension that would bin my data according to the following definitions:
Yesterday
Week to date (e.g. on Thursday, Sunday through Wednesday
data would be displayed etc.)
Last 7 days
Month to date
Last full month
Last 3 months
Last 6 months
Last 12 months
I'm not looking to create a parameter that the user would use to toggle; rather, I want a new dimension that would be dropped in the columns section that would follow the bins outlined above.
Below is an illustration of what I want to achieve:
Currently, I have the below result using this code:
IF [In Date] = DATEADD('day', -1, TODAY()) THEN 'Yesterday'
ELSEIF [In Date] < TODAY() AND [In Date] >= DATEADD('day', -ISOWEEKDAY(TODAY()), TODAY()) then 'Week to Date'
ELSEIF [In Date] < TODAY() AND [In Date] >= DATEADD('day', -7, TODAY()) THEN 'Last 7 Days'
ELSEIF [In Date] < TODAY() AND [In Date] >= DATEADD('day', -day(TODAY())+1, TODAY()) then 'Month to Date'
ELSEIF [In Date] < DATETRUNC('month', TODAY()) AND [In Date] >= DATEADD('month', -1, DATETRUNC('month', TODAY())) then 'Last Month'
ELSEIF [In Date] < DATETRUNC('month', TODAY()) AND [In Date] >= DATEADD('month', -3, DATETRUNC('month', TODAY())) then 'Last 3 Months'
ELSEIF [In Date] < DATETRUNC('month', TODAY()) AND [In Date] >= DATEADD('month', -6, DATETRUNC('month', TODAY())) then 'Last 6 Months'
ELSEIF [In Date] < DATETRUNC('month', TODAY()) AND [In Date] >= DATEADD('month', -12, DATETRUNC('month', TODAY())) then 'Last 12 Months'
ELSE 'Older' END
The overlapping date bins are not capturing all of the data: "last 12 months" omits metrics previously captured in the "last 6 months," etc. Moreover, the first 4 bins (yesterday, WTD, last 7 days, and MTD) are missing entirely.

This is a proper case of use of PARAMETERS in Tableau. I enjoyed while solving this.
Since you have not provided any data, I created a dummy data in excel by generating dates from 1-7-2020 onwards till date (DATE_GIVEN) and filling some random numbers against these as MEASURE_1. Something like this.
Now proceed like this.
Step-1 Create a parameters with 8 inputs (as listed in your question). I created for first 6 and leaving remaining for you. The parameter should be like
Step-2 Create a calculated field date bins with the following calculation
CASE [Parameter 1]
WHEN 1 THEN (
IF [Date_Given] = DATEADD('day', -1, TODAY()) THEN [Date_Given] end)
WHEN 2 THEN
( IF [Date_Given] < TODAY() AND [Date_Given] >= DATEADD('day', -ISOWEEKDAY(TODAY()), TODAY()) then [Date_Given] END )
WHEN 3 then
( IF [Date_Given] < TODAY() AND [Date_Given] >= DATEADD('day', -7, TODAY()) THEN [Date_Given] END )
WHEN 4 THEN
( IF [Date_Given] < TODAY() AND [Date_Given] >= DATEADD('day', -day(TODAY())+1, TODAY()) then [Date_Given] END )
WHEN 5 THEN
( IF [Date_Given] < DATETRUNC('month', TODAY()) AND [Date_Given] >= DATEADD('month', -1, DATETRUNC('month', TODAY())) then [Date_Given] END)
WHEN 6 THEN
( IF [Date_Given] < DATETRUNC('month', TODAY()) AND [Date_Given] >= DATEADD('month', -3, DATETRUNC('month', TODAY())) then [Date_Given] END)
END
Needless to say you have to incorporate appropriate calculation for remaining two values
Step-3 Place date bins on rows shelf and additionally on FILTERS CARD. (Filter out only null values from this .. special values tab). Add measure_1 to desired type. Show parameter 1 and your view is ready. Check the screenshots (Today's system date - 16-12-2020)
OR
OR
OR

As regards your edited question, I propose a workaround (because creation of a calculated field where one value input can result in multiple value outputs seems illogical and impossible to me given the basic rules of mathematics) as follows.
Create 8 different calculated fields as
Last 3 months M
IF [Date_Given] < DATETRUNC('month', TODAY()) AND [Date_Given] >= DATEADD('month', -3, DATETRUNC('month', TODAY())) then [Measure_1] END
similarly for other desired bins create a separate calculated field. You can thereafter build a view/viz as included in your question.

Related

How to group data from 26th of a month to 25th of the next month using postgresql?

I want to define the start of a “month” as the 26th day of the previous calendar month (and of course ending on 25th).
How can I group by this definition of month using date_trunc()?
This expression gives the month you want:
date_trunc(
'month',
date_add(
day,
case
when extract(day from date) > 25 then 7
else 0
end),
my_date_col
)
)
Select it and group by it.
The logic is: If the day of the month is greater than 25, then add some days to bump it into the next month before truncating it to the month.
I would use an INTERVAL to calculate the correct dates. Here an example using generate_series():
SELECT d::date as reference_date
, (d + interval '25 days')::date AS first_day
, (d + interval '1 month' + interval '24 days')::date as last_day
FROM generate_series('2020-01-01'::timestamp, '2021-01-01'::timestamp, '1 month') g(d);

To get weekday between two date in Postgresql

I need to get all week days in a given time interval.
In postgresql, there are dow and isodow
By mixing them together, may I write a function to retrieve weekdays?
demo:db<>fiddle
SELECT
generated_date,
to_char(generated_date, 'Day'), -- 1
EXTRACT(isodow FROM generated_date), -- 2
EXTRACT(dow FROM generated_date) -- 3
FROM
generate_series('2020-11-01'::date, '2020-11-10'::date, interval '1 day') AS generated_date
Returns the name for the weekday
Returns the number of the weekday (Monday = 1, Sunday = 7)
Returns the number of the weekday (Sunday = 0, Saturday = 6)
Edit:
If you want to get the days without weekend, you can filter by the dow/isodow values, e.g.:
SELECT
generated_date::date
FROM
generate_series('2020-11-01'::date, '2020-11-10'::date, interval '1 day') AS generated_date
WHERE
EXTRACT(isodow FROM generated_date) < 6
As far as I understand you need to extract all Monday..Fridays between two dates. Here is an illustration with 2020-11-30 as the beginning of the interval and 2020-12-12 as the end of it.
select d
from generate_series('2020-11-30'::date, '2020-12-12'::date, '1 day'::interval) t(d)
where extract(isodow from d) between 1 and 5;

Percentage of quarter passed

I'm trying to create a calculated field which shows what percentage of the quarter has passed so far. This is what I have come up with:
DATEDIFF('day',DATETRUNC('quarter',[Max Date in quarter]),[Max Date in quarter]) //days past in the quarter so far
/
//total days in quarter
IF (DATEPART('quarter', TODAY()) = 1) THEN
DATEDIFF('day', #2019-01-01#, #2019-03-31#)
ELSEIF (DATEPART('quarter', TODAY()) = 2) THEN
DATEDIFF('day', #2019-04-01#, #2019-06-30#)
ELSEIF (DATEPART('quarter', TODAY()) = 3) THEN
DATEDIFF('day', #2019-07-01#, #2019-09-30#)
ELSEIF (DATEPART('quarter', TODAY()) = 4) THEN
DATEDIFF('day', #2019-10-01#, #2019-12-31#)
END
[Max Date in Quarter] looks like:
{ FIXED YEAR([Yyyy Mm Dd]), DATETRUNC('quarter',[Yyyy Mm Dd]): MAX([Yyyy Mm Dd])}
However, it doesn't seem to work as expected. For Q1 2019 I get 97.8% and for Q2 2019 I get 98.9%. I would expect both to be 100%.
Additionally, is there a way I could dynamically update the year so when it's 2020, I won't get caught up and need to manually change the dates here?
I achieved the correct percentage by using the below:
//days past in the quarter so far
IF (DATEPART('quarter', [Max Date in quarter]) = 1) THEN
DATEDIFF('day', #2019-01-01#, today())
ELSEIF (DATEPART('quarter', [Max Date in quarter]) = 2) THEN
DATEDIFF('day', #2019-04-01#, today())
ELSEIF (DATEPART('quarter', [Max Date in quarter]) = 3) THEN
DATEDIFF('day', #2019-07-01#, today())
ELSEIF (DATEPART('quarter', [Max Date in quarter]) = 4) THEN
DATEDIFF('day', #2019-10-01#, today())
END
/
//total days in quarter
IF (DATEPART('quarter', [Max Date in quarter]) = 1) THEN
DATEDIFF('day', #2019-01-01#, [Max Date in quarter])
ELSEIF (DATEPART('quarter', [Max Date in quarter]) = 2) THEN
DATEDIFF('day', #2019-04-01#, [Max Date in quarter])
ELSEIF (DATEPART('quarter', [Max Date in quarter]) = 3) THEN
DATEDIFF('day', #2019-07-01#, [Max Date in quarter])
ELSEIF (DATEPART('quarter', [Max Date in quarter]) = 4) THEN
DATEDIFF('day', #2019-10-01#, [Max Date in quarter])
END

SSRS Default Start/End Dates Return a period of specific dates

I'm trying to write an expression in SSRS:
If today's DAY is <= 15th day, return pay period previous month 16th to last day of month
If today's DAY is >= 16th day, return current month day 1st to 15th
This is the expression I have now but its not working:
Start Date:
=IIF(DAY(TODAY) <= 15, DateAdd(DateInterval.Day, 1-Day(Today), Today), DateAdd(DateInterval.Month, -1, (DateAdd(DateInterval.Day, 16-Day(Today), Today)))),
IIF(DAY(TODAY) >= 16, dateadd("m",0,dateserial(YEAR(Today),MONTH(Today),1)
End Date:
=IIF(DAY(TODAY) <= 15, DateAdd(DateInterval.Day, -1, DateSerial(Year(Date.Now), Month(Date.Now), 1)),
IIF(DAY(TODAY) >= 16, dateadd(dd,datediff(dd,datepart(dd,getdate()),15),getdate())
I just had to do something similar in the past week...
--StartDate, if current day is more than 16, set to 1, else 16
=iif(DatePart("d",Today) >= 16, DateSerial(Year(Today), Month(Today), "1").AddMonths(-1), DateSerial(Year(Today), Month(Today),"16").AddMonths(-1))
--EndDate, if current day is more than 16 set to 15, else month end
=iif(DatePart("d",Today) >= 16, DateSerial(Year(Today), Month(Today), "15").AddMonths(-1), DateSerial(Year(Today), Month(Today),"1").AddDays(-1))
Use the following expressions
StartDate:
=
Iif ( Day(Today())>15
, DateAdd( "d", -Day(Today())+1, Today())
, DateAdd("d", -Day(Today())+16, DATEADD("m", -1,Today()))
)
EndDate:
=
Iif ( Day(Parameters!DateParam.Value)>15
, DateAdd("d", -Day(Today())+15 , Today())
, DateAdd("d", -Day( Today()) , Today())
)

Tableau - Running Total for Previous 24 Months

How can I make something like this? Note that ordering of Month was dependent in Parameter(Display Date). Parameter(Display Date) presents the last month to display.
Those line represent the following:
Will this be possible for tableau?
I'm going to assume that your date field is called Date and that the value you're measuring is called Value.
You just need two calculated fields:
Last Year / Current Year:
IF DATETRUNC('month', [Display Date]) >= DATETRUNC('month', [Date])
AND DATEADD('month', -11, DATETRUNC('month', [Display Date])) <= DATETRUNC('month', [Date])
THEN 'Current Year'
ELSEIF DATEADD('year', -1, DATETRUNC('month', [Display Date])) >= DATETRUNC('month', [Date])
AND DATEADD('month', -23, DATETRUNC('month', [Display Date])) <= DATETRUNC('month', [Date])
THEN 'Last Year'
END
There's a solid chance that it's possible to shorten that, but it gets the job done. The DATETRUNCs are to make sure that dates from the entire month are considered. Note that if a date is not in the current year or last year, then this field will be null.
Toss MONTH(Date) in the Columns shelf (make sure it's discrete), and toss SUM(Value) in the Rows shelf. Add Last Year / Current Year to the Color shelf to split the line into two, and then filter out the nulls for your Last Year / Current Year field.
At this point, everything should be working except that your chart starts with January (or the beginning of your fiscal year). We'll need to make a sort field.
Month Sort Field:
(MONTH([Date]) + (11 - MONTH([Display Date]))) % 12
This will assign a number from 1 - 12 to each date, with 12 being the month of Display Date and 1 being the month after Display Date.
Now right click on the MONTH(Date) in the Columns shelf and hit Sort.... Go to Field, choose Month Sort Field, and your months will sort such that Display Date is the final month on the axis.