How to Find Week number, Period and year from Date in Redshift? (Week Starting with Wednesday and ends up with Tuesday) - sql

Need to find weekNumber like 1,2,3,4 but the week starts with Wednesday and ends with Tuesday from date column and after the 4th week, again the week restart by again as the 1st week and so on (no need to consider month).
Need to find the Period based on weekNumber only, 4 weeks as 1 Period and Periods end with 13 (period 1-13) will restart again 1st period.
(4 weeks = 1 period) (no need to consider month).
Now need to calculate the businessyear based on Period. 13 Periods as One businessyear. (13 periods = 1 year)
Calculation logic:
7 days * 4 weeks = 28 days = 1 period
13 periods = 1 businessyear
Example:
A year has 365 days normally
In my scenario, 4 weeks * 7 days = 28 days
28 days *13 periods = 364 days
The remaining days will come as the 5th week and period 14.
Datekey date Year semistor Quarter Month DayName DayNum Wnumber
20090101 01-01-2009 2009 1 1 January 1 Thursday 1 0
20090102 02-01-2009 2009 1 1 January 1 Friday 2 0
20090103 03-01-2009 2009 1 1 January 1 Saturday 3 0
20090104 04-01-2009 2009 1 1 January 1 Sunday 0
20090105 05-01-2009 2009 1 1 January 1 Monday 0
20090106 06-01-2009 2009 1 1 January 1 Tuesday 6 0
20090107 07-01-2009 2009 1 1 January 1 Wednesday 0 0
20090108 08-01-2009 2009 1 1 January 1 Thursday 1 1
20090109 09-01-2009 2009 1 1 January 1 Friday 2 1
20090110 10-01-2009 2009 1 1 January 1 Saturday 3 1
20090111 11-01-2009 2009 1 1 January 1 Sunday 4 1
20090112 12-01-2009 2009 1 1 January 1 Monday 5 1
20090113 13-01-2009 2009 1 1 January 1 Tuesday 6 1
20090114 14-01-2009 2009 1 1 January 1 Wednesday 0 1
No need to consider the month in my scenario, need to consider leap year also (2016, 2020).

The traditional way to do this type of thing is to create a calendar table in the database. Then, your queries can simply JOIN to the calendar table to extract the relevant value.
I find that the easiest way to create the calendar table is to use Excel. Simply write some formulas that provide the desired values and Copy Down for the next decade or so. Then, save the sheet as CSV and load it into the database.
This way, you can totally avoid complex calculations involving database functions and you can use whatever rules you wish.

Related

Determine the first occurrence of a particular customer visiting the store in a particular month

I need to determine the counts breakdown to per month (and year) of customers [alias'ed as Patient_ID] which made their first visit to a store. The date times of store visits are stored in the [MDT Review Date] column of the table.
Customers can come to the store multiple times throughout the year and increase the total count-> but what I require is ONLY the first time a customer visited.
E.g. Tom Bombadil visited the store once in January 2019, so count increased to 1, then again 4 times in March, so count should be 1 for the month of March and 0 for febraury and 1 for January, then again 4 times in October, then again 2 times in December.
I require that Tom Bombadil should be counted one and only once for a particular month, his first occurrence which was per month
The output should be like :
rn1 YEAR Month_Number Month Total_Count
1 2010 6 June 2
1 2010 7 July 1
1 2010 8 August 5
1 2010 10 October 5
1 2010 11 November 3
1 2011 1 January 4
1 2011 2 February 6
1 2011 4 April 7
1 2011 5 May 4
1 2011 6 June 10
1 2011 7 July 10
1 2011 8 August 14
1 2011 9 September 4
1 2011 10 October 8
1 2011 11 November 11
1 2011 12 December 11
1 2012 1 January 8
1 2012 2 February 21​
Please refer to my query. What I have attempts to use the windowing function COUNT to count the store visits per month. Then the ROW_NUMBER function attempts to assign a unique number to each visit. What am I doing wrong?
select
*
from
(select distinct
row_number() over (partition by p.Patient_ID, p.PAT_Forename1, p.PAT_Surname
order by PAT_Forename1, p.Patient_ID, PAT_Surname) AS rn1,
datepart(year, [DATE_COLUMN]) as YEAR,
datepart(month, [DATE_COLUMN]) as Month_Number,
datename(month,[DATE_COLUMN]) as Month,
count(p.Patient_ID) over (partition by datepart(year,[DATE_COLUMN]),
datename(month, [DATE_COLUMN])) as Total_Count
from
Tablename m
inner join
TableName p on m.PK_ID = p.PK_ID
) as temp
where
rn1 = 1​

Excel: No. of Weekdays in a given week

My Data
A B C
1 Created Date Week No. of WorkDays
2 6/20/2018 11:36 06-w4 5
3 6/26/2018 12:56 06-w5 5
4 7/6/2018 23:01 07-w1 5
5 6/18/2018 18:11 06-w4 5
6 6/15/2018 12:01 06-w3 5
7 6/1/2018 13:31 06-w1 1
8 6/8/2018 12:17 06-w2 5
9 6/1/2018 13:32 06-w1 1
10 7/30/2018 13:32 07-w5 2
I have a week function that says whether an issue was created in Week 1 or 2 or so on. But for my calculation I need to consider workdays in that week, how do I do it. I'm calculating the no. of weekdays in that week manually now.
For example: June Week 1: No. of Weekdays is 1, because June 1 is Friday and June 2 is Saturday. Similarly for July Week 5 it is 2 days because July 29 is Sunday, July 30 & 31 are the weekdays.
My current formula for Week is
=CONCATENATE(TEXT(A1,"MM"),"-w",WEEKNUM(A1,1)-WEEKNUM(DATE(YEAR(A1),MONTH(A1),1),1)+1)
I'm trying out to use Workday function, but it does not provide my desired result.
Kindly help me out with this.
If the date in the A column is always a weekday, you can use this:
If that date can also be a weekend day, it will take the working days of the previous week. If you want to take the workinf days of the next week, you have to fiddle around still a bit.
=MIN(5,IF(MONTH(A2-WEEKDAY(A2,3))<MONTH(A2),7-WEEKDAY(DATE(YEAR(A2),MONTH(A2),1),1),IF(MONTH(A2+5-WEEKDAY(A2,2))>MONTH(A2),WEEKDAY(DATE(YEAR(A2),MONTH(A2)+1,0),2),5)))
First MIN: restrict to max 5 working days
First IF(): check if monday before or on date in A2 is in previous month
If so: take 7 minus weekday of first of month (sunday being 1)
If not so: second IF: check if friday this week is in next month
If so: take the weekday of the last of this month (monday being 1)
If not so: week in the middle of month, return 5
This of course does not take into account public holidays, only weekends.
For an inclusive # or workdays (e.g. Friday is 1 workday) try,
=NETWORKDAYS.INTL(A2, A2+5-WEEKDAY(A2,2), 1)
NETWORKDAYS.INTL allows for an optional holiday list if you want to create one.
Wrote my own VBA Formula - Results are as below
A B C D
1 Created Date Week No. of WorkDays No. of Days - Formula
2 6/20/2018 11:36 06-w4 5 5
3 3/2/2018 12:56 03-w1 2 2
4 7/6/2018 23:01 07-w1 5 5
5 6/18/2018 18:11 06-w4 5 5
6 6/15/2018 12:01 06-w3 5 5
7 6/1/2018 13:31 06-w1 1 1
8 6/8/2018 12:17 06-w2 5 5
9 6/1/2018 13:32 06-w1 1 1
10 7/30/2018 13:32 07-w5 2 2
Formula
=CalculateWorkdaysInWeek(A2)
VBA Code
Function CalculateWorkdaysInWeek(WeekRange As Range) As Variant
'Assume Week 2, 3 & 4 will always have 5 days
Dim WeekNo As Double
'Check if Week is 1 or 5
WeekNo = (Application.WorksheetFunction.WeekNum(WeekRange, 1) - _
Application.WorksheetFunction.WeekNum(DateSerial(Year(WeekRange), Month(WeekRange), 1))) + 1
Dim NoOfWeekDays As Integer
If WeekNo = 1 Then
FirstWeekDay = 7 - Weekday(DateSerial(Year(WeekRange), Month(WeekRange), 1), vbSunday)
If FirstWeekDay > 5 Then
FirstWeekDay = 5
End If
NoOfWeekDays = FirstWeekDay
ElseIf WeekNo = 5 Then
'Check the last day of the month as Monday as Start
LastWeekDay = Weekday(DateSerial(Year(WeekRange), Month(WeekRange) + 1, 0), vbMonday)
If LastWeekDay > 5 Then
LastWeekDay = 5
End If
NoOfWeekDays = LastWeekDay
Else ' Week 2,3 & 4 Return 5
NoOfWeekDays = 5
End If
CalculateWorkdaysInWeek = NoOfWeekDays
End Function

PLsql or Oracle Sql

Looking for a help on populating the data from table1 to table2.
I have table1 of below columns and data sample as below.
When days is 5 it needs to populate data on other table2 with 8 hours based on days (sat and sun needs to be 0 )
Table 1:
id year month days
101 2017 September 5
102 2017 September 4
103 2017 September 3
104 2017 September 2
Table 2 which needs to be populated as below:
Id Month 1 2(Sat) 3(Sunday) 4 5
101 September 8 0 0 8 8 8 8
102 September 8 0 0 8 8 8 0
103 September 8 0 0 8 8 0 0
104 September 8 0 0 8 0 0 0
You get the desired result with:
select
id,
month,
case when days >= 1 then 8 end as friday,
0 as saturday,
0 as sunday,
case when days >= 2 then 8 end as monday,
case when days >= 3 then 8 end as tuesday,
case when days >= 4 then 8 end as wednesday,
case when days >= 5 then 8 end as thursday
from table1
where year = 2017;
In order to fill table2 with this data, you can use an insert select:
insert into table2 (id, month, saturday, sunday, monday, tuesday, wednesday, thursday)
select
id,
...
from table1
where year = 2017;

Take one month back in teradata sql

I have some tables (samples are brought here) like this
scores (the score is calculated once in each month for each branch_cust in the 28 for specific month)
Branch_cust model_date score
1 28/12/2013 4
1 28/01/2014 3
1 28/02/2014 2
1 28/03/2014 7
1 28/04/2014 3
1 28/05/2014 5
1 28/06/2014 6
2 28/12/2013 9
2 28/01/2014 10
2 28/02/2014 12
2 28/03/2014 11
2 28/04/2014 10
2 28/05/2014 7
2 28/06/2014 8
loans:
Branch_cust agreement_date
1 05-01-2014
1 29-01-2014
2 27-02-2014
2 28-02-2014
Loans:
desired output:
Branch_cust agreement_date loan_open_score
1 05-01-2014 4
1 29-01-2014 3
2 27-02-2014 10
2 28-02-2014 12
Logic to create the loan_open_score :
If the day in the month of the agreement_date is less then "28" then bring the score of the month previous to the month of the agreement date.
If the day is greater or equal to "28" then bring the score for the month equal to the month of the agreement date.
Example: In the sample data for branch_cust = 1 the agreement_date was 05-01-2014 - meaning - day = 5 so I need to go back to Dec 2013 and take the score from there.
Any help how to do this? thank's. I was thinking of "join" and then substract 1 in "case of.." but I don't know how to handle the case when the date is 'dd-01-YYYY' in sql-teradata.
updated : column data type of the dates are dates.
trunc(agreement_date,'mon') + 27 returns the 28th of the current month. Now you can apply some logic and join on this calculated date:
case when trunc(agreement_date,'mon') + 27 > agreement_date
then add_months(trunc(agreement_date,'mon') + 27,-1)
else trunc(agreement_date,'mon') + 27
end
Another option would be to get the latest model_date per agreement date and join it to the scores table. This way you don't have to manipulate dates.
select t.branch_cust,t.agreement_Date,s.score
from scores s
join (select distinct l.branch_cust,l.agreement_Date
,max(s.model_Date) over(partition by l.branch_cust,l.agreement_Date) as max_model_Date
from scores s
join loans l on s.branch_cust=l.branch_cust and l.agreement_Date >= s.model_Date
) t
on s.branch_cust=t.branch_cust and s.model_Date=t.max_model_Date
select *
from scores as s
join loans as l
on l.Branch_cust =
s.Branch_cust
and l.model_date =
add_months
(
trunc(S.agreement_date,'mm')+27
,case when extract(day from s.agreement_date) < 28 then -1 else 0 end
)

distribute a value starting from the first months

let be a query such as the following.
Select MONTH, sum(RECEIVABLES), sum(COLLECTED) from TABLE1 group by MONTH
result
MONTH RECEIVABLES COLLECTED
JANUARY 2 0
FEBRUARY 1 0
MARCH 3 0
Now, APRIL 4 get made COLLECTED ...
Question: APRIL 4 in value, starting from the first month , we distribute according to how COLLECTED column.
as follows
MONTH RECEIVABLES COLLECTED
JANUARY 2 2
FEBRUARY 1 1
MARCH 3 1
APRIL 0 0
With SQL or stored procedures...
thanks...