I want to add a column to my date dimension that contains the date of the first day of that week. here's a piece of what it looks like
CalendarDate DayOfWeekNumber DayKey DayOfWeekName WeekNumber
1996-01-01 2 19960101 MONDAY 1
1996-01-02 3 19960102 TUESDAY 1
1996-01-03 4 19960103 WEDNESDAY 1
1996-01-04 5 19960104 THURSDAY 1
1996-01-05 6 19960105 FRIDAY 1
1996-01-06 7 19960106 SATURDAY 1
1996-01-07 1 19960107 SUNDAY 1
1996-01-08 2 19960108 MONDAY 2
1996-01-09 3 19960109 TUESDAY 2
1996-01-10 4 19960110 WEDNESDAY 2
1996-01-11 5 19960111 THURSDAY 2
1996-01-12 6 19960112 FRIDAY 2
1996-01-13 7 19960113 SATURDAY 2
1996-01-14 1 19960114 SUNDAY 2
So basically i would want a column WeekStartDate that, for each WeekNumber would have the CalendarDate of the first dayOfWeekNumber (dayOfWeekNumber =1)
It would look like
CalendarDate DayOfWeekNumber DayKey DayOfWeekName WeekNumber WeekStart
1996-01-01 2 19960101 MONDAY 1 1996-01-01
1996-01-02 3 19960102 TUESDAY 1 1996-01-01
1996-01-03 4 19960103 WEDNESDAY 1 1996-01-01
1996-01-04 5 19960104 THURSDAY 1 "
1996-01-05 6 19960105 FRIDAY 1 "
1996-01-06 7 19960106 SATURDAY 1 "
1996-01-07 1 19960107 SUNDAY 1 "
1996-01-08 2 19960108 MONDAY 2 1996-01-08
1996-01-09 3 19960109 TUESDAY 2 "
1996-01-10 4 19960110 WEDNESDAY 2 "
1996-01-11 5 19960111 THURSDAY 2 "
1996-01-12 6 19960112 FRIDAY 2
1996-01-13 7 19960113 SATURDAY 2
1996-01-14 1 19960114 SUNDAY 2
so something like
update myTable set WeekStartDate = CalendarDate where dayofweeknumber=2 (monday) for each weeknumber (pseudocode, i know that's not what literally what i want it to do).
Thanks for suggestions. Pretty sure I need to window on weeknumber.
UPDATE C
SET WeekStartDate = week_start
FROM
(
select *, week_start = min(CalendarDate)
over (partition by year(CalendarDate), WeekNumber)
from Calendar
) AS C
Related
I have data of stock
date open high low close volume day_name
9 2022-06-14 00:00:00+05:30 33180.60 33618.15 33123.90 33311.35 0 Tuesday
10 2022-06-15 00:00:00+05:30 33317.80 33554.55 33249.55 33339.00 0 Wednesday
11 2022-06-16 00:00:00+05:30 33648.80 33756.50 32537.95 32617.10 0 Thursday
12 2022-06-17 00:00:00+05:30 32393.45 32889.80 32290.55 32743.05 0 Friday
13 2022-06-20 00:00:00+05:30 32873.40 32923.75 32455.00 32762.50 0 Monday
And I want to query if stock changes from Friday to Wednesday by more than 5% then what is the historical change on Thursday / Next Week / etc...
I tried to set Friday as the first day of the week but was not able to get a clue about what to do next
data_frame['date'] = pandas.to_datetime(data_frame['date'])
data_frame['day_name'] = data_frame['date'].dt.day_name()
data_frame['change'] = data_frame['close'].pct_change(periods=1)
mask_map = data_frame.day_name == 'Friday'
data_frame['avg'] = data_frame.change.mask(mask_map).rolling(5, min_periods=1).mean().round(2)
I'm trying to figure out how to produce this result in SQL using pivot table Sorted by SubID
units
Sub
SubCode
AM
PM
3
Math
M2201
Monday / 7:00AM-8:00AM
Tuesday / 1:00PM-2:00PM
3
Science
S2203
Monday / 9:00AM-10:00AM
Tuesday / 3:00PM-4:00PM
3
Comp (lab)
C2203
Friday / 9:00AM-10:00AM
Wednesday / 3:00PM-4:00PM
2
Comp (lec)
C2203
Thursday / 9:00AM-10:00AM Friday / 7:00AM-8:00AM
Tuesday / 3:00PM-4:00PM
Originally, I have 3 tables where I pull out data.
table SetSub
ssID
AY
Prog
YLev
Sem
SubCode
1
2022-2023
Intermediate
3
2
M2201
2
2022-2023
Intermediate
3
2
S2203
2
2022-2023
Intermediate
3
2
C2203
table Sched
schedID
Prog
Sem
SubCode
Sub
Units
Shift
SubType
Day
Sched
isLecLab
1
Intermediate
2
M2201
Math
3
AM
Lec
Monday
7:00AM-8:00AM
0
2
Intermediate
2
M2201
Math
3
PM
Lec
Tuesday
1:00PM-2:00PM
0
3
Intermediate
2
S2203
Science
3
AM
Lec
Monday
9:00AM-10:00AM
0
4
Intermediate
2
S2203
Science
3
PM
Lec
Tuesday
3:00PM-4:00PM
0
5
Intermediate
2
C2203
Comp
2
AM
Lec
Thursday
9:00AM-10:00AM
1
6
Intermediate
2
C2203
Comp
2
AM
Lec
Friday
7:00AM-8:00AM
1
7
Intermediate
2
C2203
Comp
2
PM
Lec
Tuesday
3:00PM-4:00PM
1
8
Intermediate
2
C2203
Comp
3
AM
Lab
Friday
9:00AM-10:00AM
1
9
Intermediate
2
C2203
Comp
3
PM
Lab
Wednesday
3:00PM-4:00PM
1
table Subjects
subid
Sub
SubCode
Units
isLecLab
1
Math
M2201
3
0
2
Science
S2203
3
1
3
Comp
C2203
5
0
Added an image since table get messed up upon saving the post
But created a new table for this.
subid
units
sub
UserCode
Shift
Sched
1
3
Math
M2201
AM
Monday / 7:00AM-8:00AM
1
3
Math
M2201
PM
Tuesday / 1:00PM-2:00PM
2
3
Science
S2203
AM
Monday / 9:00AM-10:00AM
2
3
Science
S2203
PM
Tuesday / 3:00PM-4:00PM
3
3
Comp (lab)
C2203
AM
Friday / 9:00AM-10:00AM
3
2
Comp (lab)
C2203
PM
Wednesday / 3:00PM-4:00PM
3
3
Comp (lec)
C2203
AM
Thursday / 9:00AM-10:00AM
3
2
Comp (lec)
C2203
PM
Tuesday / 3:00PM-4:00PM
3
2
Comp (lec)
C2203
PM
Friday / 7:00AM-8:00AM
I tried several queries and the closest I've got is this
units
Sub
Code
AM
PM
3
Math
M2201
Monday / 7:00AM-8:00AM
Tuesday / 1:00PM-2:00PM
3
Science
S2203
Monday / 9:00AM-10:00AM
Tuesday / 3:00PM-4:00PM
3
Comp (lab)
C2203
Thursday / 9:00AM-10:00AM
Tuesday / 3:00PM-4:00PM
3
Comp (lab)
C2203
Friday / 9:00AM-10:00AM
Wednesday / 3:00PM-4:00PM
2
Comp (lec)
C2203
Thursday / 9:00AM-10:00AM
Tuesday / 3:00PM-4:00PM
2
Comp (lec)
C2203
Friday / 9:00AM-10:00AM
Wednesday / 3:00PM-4:00PM
Second data for AM of comp (lec) didn't appear.
Here's the code I've tried
select a.usercode, a.sub, a.Units, a.am, b.pm, a.Schedid from
(select * from
(select distinct subid, usercode, sub, units, shift, sched from Table1 where shift= 'am') as src
pivot (max(sched) for shift in ("am")) as pvt ) as A
inner join
(select * from
(select distinct subid, usercode, sub, units, shift, sched from table1 where shift= 'pm') as src2
pivot (max(sched) for shift in ("pm")) as pvt2 ) as B on a.shift= b.shift
Conditional agg will perform a pivot, and it's eaier to perform more advanced operations using it than PIVOT does, so it's a pattern worth learning.
To see how a conditional agg works, remove the GROUP BY and any mention of a MIN/MAX/STRING_AGG or other agregating operation. It makes it easier to see that a vertical arrangement of data:
A, 1
B, 2
C, 1
Becomes diagonal when CASE WHEN'd:
--CASE WHEN letter = 'A' then number end as a,
--CASE WHEN letter = 'B' then number end as b,
--CASE WHEN letter = 'C' then number end as c,
A, B, C
1, -, -
-, 2, -
-, -, 3
The GROUP/MAX then flattens the nulls out, so the "diagonal" data is fully rotated to horizontal
--MAX(CASE WHEN letter = 'A' then number end) as a,
--MAX(CASE WHEN letter = 'B' then number end) as b,
--MAX(CASE WHEN letter = 'C' then number end) as c,
A, B, C
1, 2, 3
In your requirement, using STRING_AGG allows multiple values per cell rather than just one
This form is for use on your joined table because I cannot make assumptions about the 3 tables that generated it (no detail)
Something like this should work for SQLS..
SELECT
CASE WHEN Sub = 'Comp (lec)' THEN MIN(Units) ELSE MAX(Units) END as Units,
Sub,
MAX(UserCode) as UserCode,
STRING_AGG(CASE WHEN Shift = 'AM' THEN Sched END, CHAR(10)) as AM,
STRING_AGG(CASE WHEN Shift = 'PM' THEN Sched END, CHAR(10)) as PM
FROM
t
GROUP BY
Sub
..but it'd be good to see the source tables/the query that generated t. Getting the data in the exact order per cell (making sure that the cell says "Thursday..Friday" rather then "Friday..Thursday" might be really messy. It would help if these things were numeric/dates somewhere. Post the original data so we can see if it helps)
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.
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
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;