Bigquery YTD WORKDAYS calculation - sql

I use the below calc to calculate workdays in a month.
i.e for calendar date = 28-05-2021 , i get 23 days ( monday to friday)
(select count(*) from unnest(generate_date_array(date_trunc(CALENDAR_DATE, month), last_day(CALENDAR_DATE, month ))) day
where not extract(dayofweek from day) in (1, 7)) as Workdays_Month,
I would like to calculate YTD Workdays based on the Calendar Date
i.e
if calendar date = 28-05-2021 then YTD workdays would be sum of workdays in months ( Jul 20 to May 21) financial year.

Assuming your financial year starts in July - you can use below
select count(*)
from unnest([struct(extract(year from current_date) as year, extract(month from current_date) as month)]),
unnest(generate_date_array(if(month < 7, date(year - 1, 7, 1), date(year, 7, 1)), last_day(date(year, month, 1)))) day
where not extract(dayofweek from day) in (1, 7)

Related

SQL query to find dates of last year equivalent to today's date

I am writing a SQL query to find business working dates of last year equivalent to today's date.
In this query it should fetch :-
For e.g. if today is 5th January, 2021 and it is the second day of second week of the year. So I need to find the exact equivalent date of the second day of second week of the previous year. So it would be 7th January, 2020.
And with this, I need the business working dates of that week of 7th January 2020 (i.e. excluding Saturday & Sunday)
Which will come up as 2020-Jan-06 to 2020-Jan-10 according to the example.
So I will need the report between 6th Jan - 10th Jan, 2020.
I am trying to use this code to find date of last year equivalent to today's date (5th Jan, 2021 viz. second day of second week)
select Convert(date, (DATEADD(year, -1, getdate()+2))) ;
2021-01-05 is the 2nd day of the first week of 2021 according to ISO standards.
If you want the 2nd day of the first week of 2021, then it is either today's date minus 52 weeks or 53 weeks. Based on the Wikipedia page for ISO dates:
[53 week years are those] years in which 1 January or 31 December are Thursdays
So, we want that for the previous year. Hence, I think the following should work:
select dateadd(week,
(case when 'Thursday' in (datename(weekday, datefromparts(year(getdate()) - 1, 1, 1)),
datename(weekday, datefromparts(year(getdate()) - 1, 12, 31))
)
then -53 else -52
end),
convert(date, getdate())
)
Note that this returns 2019-12-31, which is the correct value based on ISO standards.
I have use multiple CTE to show you the step by step calculation. It should be pretty easy to follow.
Basically it find the week_no and day_no_of_week for 2021-01-05 and then use that to find the same date for 2020
declare #input_date date = '2021-01-05',
#year_offset int = -1; -- previous year
with
cte1 as
(
select input_date = #input_date,
week_no = DATEPART(WEEK, #input_date),
first_day_of_week = DATEADD(WEEK, DATEDIFF(WEEK, 0, #input_date), 0)
),
cte2 as
(
select *,
day_no_of_week = DATEDIFF(DAY, first_day_of_week, #input_date) + 1
from cte1
),
cte3 as
(
select *,
first_day_of_the_prev_year = DATEADD(YEAR, DATEDIFF(YEAR, 0, #input_date) + #year_offset, 0)
from cte2
),
cte4 as
(
select *,
first_day_of_week_prev_year = DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(WEEK, week_no - 1, first_day_of_the_prev_year)), 0)
from cte3
)
select *,
DATEADD(DAY, day_no_of_week - 1, first_day_of_week_prev_year) as the_required_date
from cte4

Current Month, Previous Month, Next Month

This is my query
select *
from RDR1 A
where Year(A.shipdate) = '2021'
and (
Month(A.shipdate) = Month(CURRENT_TIMESTAMP) - 1
or Month(A.shipdate) = Month(CURRENT_TIMESTAMP) + 1
or Month(A.shipdate) = Month(CURRENT_TIMESTAMP)
)
The above query works fine when they choose the year 2020, But when they choose 2021 it doesn't work. The above query should filter based on the current month. For eg: December 2020 (Current Month), Jan 2021 (next month), November (Previous Month).
How should I modify my query?
If you want the last month, this month, or next month, I would suggest:
where a.shipdate >= dateadd(month, -1, datefromparts(year(getdate()), month(getdate()), 1)) and
a.shipdate < dateadd(month, 2, datefromparts(year(getdate()), month(getdate()), 1))
This is index-friendly. If that is not a concern, you can use:
where datediff(month, s.shipdate, getdate()) between -1 and 1

Aggregate by week using (Sun - Sat)

SELECT
CONCAT(CAST(WEEK(CAST(date as DATE)) as VARCHAR), ' - WEEK') as week,
COUNT(DISTINCT(field1)) as field1_count,
SUM(amount) as amount
FROM table
WHERE SUBSTR(DATE, 1, 4) = '2020'
GROUP BY 1
ORDER BY 1
Is there a way to ensure that the aggregate here is Sun - Sat? This is currently aggregating at Mon - Sun
Add one day to the date:
SELECT CONCAT(CAST(WEEK(CAST(date + INTERVAL '1' DAY as DATE)) as VARCHAR), ' - WEEK') as week,

First Day of month

select distinct
DATEPART("yyyy", datum) AS year
, DATEPART("mm", datum) AS month
=
Can anybody tell my how i get the first day of the month with it. If I try "Datepart("dd", datum) As day", I get every day instead of only the first day
For SQL Server 2012+ try:
DATEFROMPARTS(YEAR(datum), MONTH(datum), 1)
You can use End of Month function (EOMONTH()) with the previous month, and add 1 day.
DECLARE #Date DATE = '2018-06-08'
SELECT
OriginalDate = #Date,
EndOfPreviousMonth = EOMONTH(#Date, -1),
StartOfMonth = DATEADD(DAY, 1, EOMONTH(#Date, -1))
First day of month is always 1st.
select distinct
DATEPART("yyyy", datum) AS year,
DATEPART("mm", datum) AS month,
1 AS FirstDayOfMonth
from qdatum
order by year, month
(I am clueless on what you are trying to achieve actually)
CREATE TABLE Table1
([datum] date)
;
INSERT INTO Table1
(datum)
VALUES
('04-06-2018')
;
SELECT distinct DATEPART("yyyy", datum) AS year
,DATEPART("mm", datum) AS month
,DATENAME(dw,CAST(DATEPART("mm", datum) AS VARCHAR)
+ '/'
+ CAST('01' AS VARCHAR)
+ '/'
+ CAST(DATEPART("yyyy", datum) AS VARCHAR)) AS [First day of month]
FROM table1
order by year, month
OutPut
year month First day of month
2018 4 Sunday
Live Demo
http://sqlfiddle.com/#!18/69402/4

First day of week (beginning with Sunday)

I found that there is a function last_day for last day of month, and date_part(dow, date) for numeric day of week starting with Sunday, but I am trying to take a date, and get the first day of that week.
Meaning: if date='2018-02-14' then result should be '2018-02-11'.
Any ideas?
You simply want to subtract the dow value from the current date.
select dateadd(d, -datepart(dow, my_date), my_date)
from (select date('2018-02-14') as my_date)
> 2018-02-11 00:00:00.0
For example, if dow is 3 for 2018-02-14 - a Wednesday - you can subtract 3 days to get back to "day 0".
There's also the date_trunc function which will truncate everything after a given datepart. This is a little clunky, and will only set you back to the previous Monday, not Sunday.
select date_trunc('week', my_date)
from (select date('2018-02-14') as my_date)
Not sure if there is a more efficient solution but:
date_trunc('week',my_date + '1 day'::interval)::date - '1 day'::interval as week_start
If you want to get First day of week with week start day is any day in the week (Monday, Tuesday, ...). You can use this way:
day_of_week_index mapping:
{
'monday': 1,
'tuesday': 2,
'wednesday': 3,
'thursday': 4,
'friday': 5,
'saturday': 6,
'sunday': 7
}
Query Template:
SELECT
CASE
WHEN extract(ISODOW FROM datetime_column) < day_of_week_index THEN cast(date_trunc('week', datetime_column) AS date) - 8 + day_of_week_index
ELSE cast(date_trunc('week', datetime_column) AS date) - 1 + day_of_week_index
END
FROM table_name;
Example:
Get First day of week with week start day is Wednesday
SELECT
CASE
WHEN extract(ISODOW FROM TIMESTAMP '2021-12-03 03:00:00') < 3 THEN cast(date_trunc('week', TIMESTAMP '2021-12-03 03:00:00') AS date) - 8 + 3
ELSE cast(date_trunc('week', TIMESTAMP '2021-12-03 03:00:00') AS date) - 1 + 3
END;
=> Result:
2021-12-01
Note: You can change the day_of_week_index following the above mapping to determine the week start day (Monday, Tuesday, ..., Sunday).