Calculate current quarter Fiscal_start date based off 13 week (91 day) rolling quarters - sql

I am looking for a SQL solution to work in Oracle Developer SQL that will calculate the current quarters start and end date based off of sysdate and that the Fiscal calendar starts on Feb 1, 2020. Each quarter is a Fixed 13 weeks (91 days) -- NOT 3 months, therefore each year has a slightly different fiscal calendar.
Code will be uploaded to automated reporting and do not want to adjust it each year.
Current year fiscal calendar attached as sample explanation.
Current Fiscal Calendar
I started to head down this road but got lost when i realized the start date wasnt able to be correct in this format.
End solution would be used for a where clause to determine reporting date range such as
( Where Report_Date between Modified_Quarter_Start and sysdate )
select trunc(add_months(add_months(trunc(sysdate,'Y') -1 ,
to_number(to_char(sysdate,'Q')) * 3),-1),'MM')
start_date,trunc(add_months(add_months(trunc(sysdate,'Y') -1 ,
to_number(to_char(sysdate,'Q')) * 3),+2),'MM')-1 Endd_date,
add_months(trunc(sysdate,'Y') -1 ,to_number(to_char(sysdate,'Q')) * 3) end_date ,
to_char(sysdate,'YYYY - q') qtr from dual
Greatly appreciate any assistance.

Posting incase someone else runs into the same predicement in the future.
After reading a mention of a case statement for fixed days in another thread, i thought of this solution.
Select Trunc(sysdate - to_date('02-Feb-2019')),
Case When Trunc(sysdate - to_date('02-Feb-2019')) > 91 Then to_date('02-Feb-2019') +
Round( to_number(Trunc(sysdate - to_date('02-Feb-2019'))/91),0) * 91
Else null End Current_Quarter_Start,
Case When Trunc(sysdate - to_date('02-Feb-2019')) > 91 Then to_date('02-Feb-2019') +
( (Round( to_number(Trunc(sysdate - to_date('02-Feb-2019'))/91),0) +1 )* 91)-1 Else null End Current_Quarter_End From Dual

Related

How do I generate a list of dates of every 7 days between a range of dates based on a date field in Oracle SQL?

I need to generate a list of week end dates based on the first week end date, and between a date range.
For example: I have a week end date of '06/04/2022'. If I enter 06/01/2022-01/01/2023 as my date parameters, I need a list of every seven days beginning on 06/04/2022 through 01/01/2023. The output would look something like this:
Dates
06/04/2022
06/11/2022
06/18/2022
.
.
.
12/24/2022
12/31/2022
Note: the initial week end date is not necessarily always on a Saturday, so it would need to be based on the actual date and not the day of the week.
I have this code which produces every day between two dates, but I need every seven days between two dates, and based on a date field retrieved from another table. I'm stuck on how to get every seven days, or every week from the date.
select (date'2022-06-04' + level - 1) dt
from dual
connect by level <= (date'2023-01-01' - date'2022-06-01' + 1)
Multiply the step size by 7:
SELECT DATE '2022-06-04' + (level - 1) * 7 AS dt
FROM dual
CONNECT BY DATE '2022-06-04' + (level - 1) * 7 <= DATE '2023-01-01'
Or, to make the calculation you are preforming more obvious that you are adding a week, you can use an INTERVAL literal:
SELECT DATE '2022-06-04' + (level - 1) * INTERVAL '7' DAY AS dt
FROM dual
CONNECT BY DATE '2022-06-04' + (level - 1) * INTERVAL '7' DAY <= DATE '2023-01-01'
You could also calculate the number of weeks required in your connect by levels code.
i.e. This would give you the number of rows required
CONNECT BY LEVEL < (DATE2 - DATE1) / 7
Notably the DATE2 - DATE1 code works because Oracle likes to think of things in terms of days. i.e. Sysdate - 1 is just yesterday. Sysdate + 1 is just tomorrow.
Then tack on a + 1 since you probably want to return 1 row in the case it's less than a week
And then doing this
SELECT DATE'2023-01-24' + (LEVEL-1) * 7
FROM DUAL
CONNECT BY LEVEL < ((SYSDATE - DATE'2023-01-24') / 7) + 1

How to get start & end of same week last year in DB2 using SQL?

I have a weekly report that uses these date parameters:
SELECT *
FROM TABLE
WHERE DATE_FIELD BETWEEN (CURRENT DATE - 8 DAYS) AND (CURRENT DATE - 2 DAYS)
This runs on Mondays to gather the previous week's data (Sun-Sat). What I want now is to run this for the same week of the previous year.
So for example, if the code above runs on Mon 29/06/20, it returns data from Sun 21/06/20 - Sat 27/06/20, i.e. week 26 of 2020. I want it to return data from Sun 23/06/19 - Sat 29/06/19, i.e. week 26 of 2019.
The report runs automatically so I can't just plug in the exact dates each time. I also can't just offset the date parameters to -357 and -367 days, as this gets thrown off by leap years.
I've searched for solutions but they all seem to rely on the DATEADD function, which my DB2 database doesn't recognise.
Does anyone know how I can get the result I'm looking for, please? Any advice would be appreciated! :)
The easiest way to do this is to build a calendar or dates table...(google sql calendar table)
Among the columns you'd have would be
date
year
month
quarter
dayofWeek
startOfWeek
endOfWeek
week_nbr
You can use the week() or week_iso() functions when loading the table, pay attention to the differences and pick the best fit for you.
Such a calendar table makes it easy to compare current period vs prior period.
If you assume that all years have 52 weeks, you can use date arithmetic:
SELECT *
FROM TABLE
WHERE DATE_FIELD BETWEEN (CURRENT DATE - (8 + 364) DAYS) AND (CURRENT DATE - (2 + 364) DAYS)
Because you want the week to start on a Monday, this doesn't have to take leap years into account. It is subtracting exactly 52 weeks -- and leap years do no affect weeks.
This gets more complicated if you have to deal with 52 or 53 week years.
A little bit complicated, but it should work. You may run it as is or test your own date.
SELECT
YEAR_1ST_WEEK_END + WEEKS_TO_ADD * 7 - 6 AS WEEK_START
, YEAR_1ST_WEEK_END + WEEKS_TO_ADD * 7 AS WEEK_END
FROM
(
SELECT
DATE((YEAR(D) - 1)||'-01-01')
+ (7 - DAYOFWEEK(DATE((YEAR(D) - 1)||'-01-01'))) AS YEAR_1ST_WEEK_END
, WEEK(D) - 2 AS WEEKS_TO_ADD
FROM (VALUES DATE('2020-06-29')) T(D)
);
The intermediate column YEAR_1ST_WEEK_END value is the 1-st Sat (end of week) of previous year for given date.
WEEKS_TO_ADD is a number of weeks to add to the YEAR_1ST_WEEK_END date.

Calculating Years, Months, Days in oracle

I am working on a program that takes takes a start date and an end date and returns separate values for Years, Months, and Days. Each category has its own section of code, this is what I have been using and so far its been semi-accurate until days (and sometimes months.I am not even trying to fool with leap-year at this point)
Ex Start: 04/10/2000 End: 04/10/2006 should give me 6 years 0 months and 0 days.
Years Code:
SELECT
trunc(months_between((to_date(:main_DT_DateEnd1,'MM/DD/YYYY')),(to_date(:main_DT_DateBeg1,'MM/DD/YYYY'))) / 12) as "Years1"
FROM dual
Months Code:
SELECT
trunc(mod(months_between((to_date(:main_DT_DateEnd1,'MM/DD/YYYY')),(to_date(:main_DT_DateBeg1,'MM/DD/YYYY'))), 12)) as "Months1"
FROM dual
Days Code: I have tried multiple versions of these without much success for example I can calculate total days between days but since there are different months in certain days dividing becomes more of a hassle. This is the closest one I am getting where if the days are the same then no calculation is needed, else subtract them using a substring.
1)
SELECT
CASE
WHEN substr((to_date(:main_DT_DateBeg1,'MM/DD/YYYY')),4,5) = substr((to_date(:main_DT_DateEnd1,'MM/DD/YYYY')),4,5)
THEN 0
WHEN substr((to_date(:main_DT_DateBeg1,'MM/DD/YYYY')),4,5) < substr((to_date(:main_DT_DateEnd1,'MM/DD/YYYY')),4,5)
THEN to_number(substr((to_date(:main_DT_DateEnd1,'MM/DD/YYYY')),4,5)) - to_number(substr((to_date(:main_DT_DateBeg1,'MM/DD/YYYY')),4,5))
END as "Days_1"
FROM dual
Thanks for your time, for those of you wondering this is for a job experience calculator :)
Please refer here for examples:
http://docs.oracle.com/cd/E11882_01/server.112/e41084/sql_elements001.htm#SQLRF50992
You can definitely use following logic to calculate years and months. In terms of the days - it's a bit tricky as for 28 Feb + 1 month returns 31 March...
select extract(year from (d2 - d1) year to month),
extract(month from (d2 - d1) year to month),
add_months(d1, extract(year from (d2 - d1) year to month)*12 + extract(month from (d2 - d1) year to month)) - d2
from (
select date'2014-08-27' as d2, date'2002-02-27' as d1
from dual
)

Number of particular days between two dates

Is there an "easy" way to calculate the count of a particular day between two dates (e.g., say I wanted to know the number of Tuesdays between 1st January, 2000 and today)? Moreover, the same question applies more broadly to different units (e.g., how many 2pms between two dates, how many Februaries, how many 21st Augusts, etc.)... The best I've come up with (for days between dates) is this:
with calendar as (
select to_char(:start + level - 1, 'DAY') dayOfWeek
from dual
connect by level <= ceil(:end - :start)
)
select dayOfWeek, count(dayOfWeek)
from calendar
group by dayOfWeek;
I would have to create a view of this -- hardcoding the start and end dates -- to make it convenient(ish) to use; either that or write a function to do the dirty work. That wouldn't be difficult, but I'm wondering if there's already an Oracle function that could do this, accounting for things like leap days, etc.
EDIT This popped up in the related links when I posted this. That more-or-less answers the question for days and I know there's a months_between function that I could use for particular months. Any other related functions I should know about?
Replace start/end dates with your dates. This query calc number of TUE from Jan 1-2013 till today, which is 18:
SELECT count(*) number_of_tue
FROM
(
SELECT TRUNC(TO_DATE(Sysdate), 'YEAR') + LEVEL-1 start_dt
, To_Char(TRUNC(TO_DATE(Sysdate), 'YEAR') + LEVEL - 1, 'DY') wk_day
, To_Char(TRUNC(TO_DATE(Sysdate), 'YEAR') + LEVEL - 1, 'D') wk_day#
, trunc(Sysdate) end_dt
FROM DUAL
CONNECT BY LEVEL <= trunc(Sysdate) - trunc(Sysdate, 'YEAR') -- replace with your start/end dates
)
WHERE wk_day# = 3 -- OR wk_day = 'TUE' --
/

SQL that list all birthdays within the next and previous 14 days

I have a MySQL member table, with a DOB field which stores all members' dates of birth in DATE format (Notice: it has the "Year" part)
I'm trying to find the correct SQL to:
List all birthdays within the next 14 days
and another query to:
List all birthdays within the previous 14 days
Directly comparing the current date by:
(DATEDIFF(DOB, now()) <= 14 and DATEDIFF(DOB, now()) >= 0)
will fetch nothing since the current year and the DOB year is different.
However, transforming the DOB to 'this year' won't work at all, because today could be Jan 1 and the candidate could have a DOB of Dec 31 (or vice versa)
It will be great if you can give a hand to help, many thanks! :)
#Eli had a good response, but hardcoding 351 makes it a little confusing and gets off by 1 during leap years.
This checks if birthday (dob) is within next 14 days. First check is if in same year. Second check is if its say Dec 27, you'll want to include Jan dates too.
With DAYOFYEAR( CONCAT(YEAR(NOW()),'-12-31') ), we are deciding whether to use 365 or 366 based on the current year (for leap year).
SELECT dob
FROM birthdays
WHERE DAYOFYEAR(dob) - DAYOFYEAR(NOW()) BETWEEN 0 AND 14
OR
DAYOFYEAR( CONCAT(YEAR(NOW()),'-12-31') ) - ( DAYOFYEAR(NOW()) - DAYOFYEAR(dob) ) BETWEEN 0 AND 14
Here's the simplest code to get the upcoming birthdays for the next x days and previous x days
this query is also not affected by leap-years
SELECT name, date_of_birty
FROM users
WHERE DATE(CONCAT(YEAR(CURDATE()), RIGHT(date_of_birty, 6)))
BETWEEN
DATE_SUB(CURDATE(), INTERVAL 14 DAY)
AND
DATE_ADD(CURDATE(), INTERVAL 14 DAY)
My first thought was it would be easy to just to use DAYOFYEAR and take the difference, but that actually gets kinda trick near the start/end of a yeay. However:
WHERE
DAYOFYEAR(NOW()) - DAYOFYEAR(dob) BETWEEN 0 AND 14
OR DAYOFYEAR(dob) - DAYOFYEAR(NOW()) > 351
Should work, depending on how much you care about leap years. A "better" answer would probably be to extract the DAY() and MONTH() from the dob and use MAKEDATE() to build a date in the current (or potential past/following) year and compare to that.
Easy,
We can obtain the nearer birthday (ie the birthday of this year) by this code:
dateadd(year,datediff(year,dob,getdate()),DOB)
use this in your compares ! it will work.
There are a number of options, I would first try to transform by number of years between current year and row's year (i.e. Add their age).
Another option is day number within the year (but then you have still to worry about the rollover arithmetic or modulo).
This is my query for the 30 days before check:
select id from users where
((TO_DAYS(concat(DATE_FORMAT(NOW(),'%Y'), '-', DATE_FORMAT(date_of_birth, '%m-%d')))-TO_DAYS(NOW()))>=-30
AND (TO_DAYS(concat(DATE_FORMAT(NOW(),'%Y'), '-', DATE_FORMAT(date_of_birth, '%m-%d')))-TO_DAYS(NOW()))<=0)
OR (TO_DAYS(concat(DATE_FORMAT(NOW(),'%Y'), '-', DATE_FORMAT(date_of_birth, '%m-%d')))-TO_DAYS(NOW()))>=(365-31)
and 30 days after:
select id from users where
((TO_DAYS(NOW())-TO_DAYS(concat(DATE_FORMAT(NOW(),'%Y'), '-', DATE_FORMAT(date_of_birth, '%m-%d'))))>=-31
AND (TO_DAYS(NOW())-TO_DAYS(concat(DATE_FORMAT(NOW(),'%Y'), '-', DATE_FORMAT(date_of_birth, '%m-%d'))))<=0)
OR (TO_DAYS(NOW())-TO_DAYS(concat(DATE_FORMAT(NOW(),'%Y'), '-', DATE_FORMAT(date_of_birth, '%m-%d'))))>=(365-30)
My solution is as follow:
select cm.id from users cm where
date(concat(
year(curdate()) - (year(subdate(curdate(), 14)) < year(curdate())
and month(curdate()) < month(cm.birthday)) + (year(adddate(curdate(), 14)) > year(curdate())
and month(curdate()) > month(cm.birthday)), date_format(cm.birthday, '-%m-%d'))) between subdate(curdate(), 14)
and adddate(curdate(), 14);
It looks like it works fine when the period captures the current and next year or the current and previous year