Oracle SQL - Last 3 full months of data - sql

I need to get the last 3 full months of data so March, April, and May in this case. This almost gives me what I want but it includes June 1st which I don't need. I need March 1st through May 31st.
Oracle SQL:
where d.D_DATE between add_months(trunc(sysdate, 'month'), -3) and add_months(trunc(sysdate, 'month'),0)

Use >= and < rather than BETWEEN:
SELECT *
FROM d
WHERE d.D_DATE >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -3)
AND d.D_DATE < TRUNC(SYSDATE, 'MM')
Which, for the sample data:
CREATE TABLE d (D_DATE) AS
SELECT ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -3) - INTERVAL '1' SECOND FROM DUAL UNION ALL
SELECT ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -3) FROM DUAL UNION ALL
SELECT TRUNC(SYSDATE, 'MM') - INTERVAL '1' DAY FROM DUAL UNION ALL
SELECT TRUNC(SYSDATE, 'MM') - INTERVAL '1' DAY FROM DUAL UNION ALL
SELECT TRUNC(SYSDATE, 'MM') - INTERVAL '1' DAY + INTERVAL '1' SECOND FROM DUAL UNION ALL
SELECT TRUNC(SYSDATE, 'MM') - INTERVAL '1' SECOND FROM DUAL UNION ALL
SELECT TRUNC(SYSDATE, 'MM') FROM DUAL;
Outputs:
D_DATE
2022-03-01 00:00:00
2022-05-31 00:00:00
2022-05-31 00:00:00
2022-05-31 00:00:01
2022-05-31 23:59:59
db<>fiddle here

Got it. where d.D_DATE between add_months(trunc(sysdate, 'month'), -3) and last_day(add_months(trunc(sysdate, 'month'),-1))

Related

Oracle DBA Scheduler Flow

I have a requirement to schedule the procedure using Oracle DBA Scheduler to run on the 4th working day every month (excluding bank holidays and weekends). After doing some research it seems that Oracle DBA Scheduler does not recognize working days or bank holidays.
I have come up with below two ideas:
schedule another procedure to run on the 1st of every month and check when is the 4th working day and adjust the repeat_interval in the first scheduled job so it runs on 4th working day.
schedule the job to run monthly but only for the first 7 days, and in the run procedure create a check if today is 4th working day and if yes then execute if not do not run.
I do not have much experience with scheduling jobs, so I am not sure if option 1 is recommended, but it seems easier. I guess option 2 is still ok, but it will be more time-consuming to complete.
What option would you use? Or maybe something completely different?
Thanks
You can have an SQL resulting with 4th working day in every month of the year. You should get holiday dates for the actual year.
Example:
Czech Republic Public Holidays 2022
Date
Day
Holiday
01.01.2022
Sat
New Year's Day
15.04.2022
Fri
Good Friday
18.04.2022
Mon
Easter Monday
01.05.2022
Sun
May Day
08.05.2022
Sun
Liberation Day
05.07.2022
Tue
St Cyril and St Methodius Day
06.07.2022
Wed
Jan Hus Day
28.09.2022
Wed
Statehood Day
28.10.2022
Fri
Independence Day
17.11.2022
Thu
Freedom and Democracy Day
24.12.2022
Sat
Christmas Eve
25.12.2022
Sun
Christmas Day
26.12.2022
Mon
2nd Day of Christmas
Create a CTE holidays and another CTE named days holding 365 days with some attributes like day of week, is it a working day or not and distinct counters for working and non working days within a month:
WITH
holidays AS
(
Select To_Date('01.01.2022', 'dd.mm.yyyy') "A_DATE", 'New Year''s Day' "A_NAME" From Dual Union All
Select To_Date('15.04.2022', 'dd.mm.yyyy') "A_DATE", 'Good Friday ' "A_NAME" From Dual Union All
Select To_Date('18.04.2022', 'dd.mm.yyyy') "A_DATE", 'Easter Monday' "A_NAME" From Dual Union All
Select To_Date('01.05.2022', 'dd.mm.yyyy') "A_DATE", 'May Day ' "A_NAME" From Dual Union All
Select To_Date('08.05.2022', 'dd.mm.yyyy') "A_DATE", 'Liberation Day' "A_NAME" From Dual Union All
Select To_Date('05.07.2022', 'dd.mm.yyyy') "A_DATE", 'St Cyril and St Methodius Day' "A_NAME" From Dual Union All
Select To_Date('06.07.2022', 'dd.mm.yyyy') "A_DATE", 'Jan Hus Day' "A_NAME" From Dual Union All
Select To_Date('28.09.2022', 'dd.mm.yyyy') "A_DATE", 'Statehood Day' "A_NAME" From Dual Union All
Select To_Date('28.10.2022', 'dd.mm.yyyy') "A_DATE", 'Independence Day' "A_NAME" From Dual Union All
Select To_Date('17.11.2022', 'dd.mm.yyyy') "A_DATE", 'Freedom and Democracy Day' "A_NAME" From Dual Union All
Select To_Date('24.12.2022', 'dd.mm.yyyy') "A_DATE", 'Christmas Eve ' "A_NAME" From Dual Union All
Select To_Date('25.12.2022', 'dd.mm.yyyy') "A_DATE", 'Christmas Day' "A_NAME" From Dual Union All
Select To_Date('26.12.2022', 'dd.mm.yyyy') "A_DATE", '2nd Day of Christmas ' "A_NAME" From Dual
),
days AS
( Select
To_Date('01.01.' || To_Char(SYSDATE, 'yyyy'), 'dd.mm.yyyy') + (LEVEL - 1) "DATE_ID",
To_Char(To_Date('01.01.' || To_Char(SYSDATE, 'yyyy'), 'dd.mm.yyyy') + (LEVEL - 1), 'DY') "DAY_OF_WEEK",
CASE
WHEN To_Char(To_Date('01.01.' || To_Char(SYSDATE, 'yyyy'), 'dd.mm.yyyy') + (LEVEL - 1), 'DY') NOT IN('SAT', 'SUN') And
To_Date('01.01.' || To_Char(SYSDATE, 'yyyy'), 'dd.mm.yyyy') + (LEVEL - 1) Not IN(Select A_DATE From holidays)
THEN 'YES'
ELSE '-'
END "WRKDAY",
Count(*) OVER(Partition By To_Char(To_Date('01.01.' || To_Char(SYSDATE, 'yyyy'), 'dd.mm.yyyy') + (LEVEL - 1), 'yyyymm') ||
CASE
WHEN To_Char(To_Date('01.01.' || To_Char(SYSDATE, 'yyyy'), 'dd.mm.yyyy') + (LEVEL - 1), 'DY') NOT IN('SAT', 'SUN') And
To_Date('01.01.' || To_Char(SYSDATE, 'yyyy'), 'dd.mm.yyyy') + (LEVEL - 1) Not IN(Select A_DATE From holidays)
THEN 'YES'
ELSE '-'
END
Order By To_Date('01.01.' || To_Char(SYSDATE, 'yyyy'), 'dd.mm.yyyy') + (LEVEL - 1)) "DAY_NUM"
From
Dual
Connect By
LEVEL <= 365
Order By
LEVEL
)
Now you can get all the dates of interest for year 2022:
Select
DATE_ID, DAY_OF_WEEK, WRKDAY, DAY_NUM
From
days
Where
WRKDAY = 'YES' And DAY_NUM = 4
Order By
DATE_ID
The result is:
DATE_ID
DAY_OF_WEEK
WRKDAY
DAY_NUM
06-JAN-22
THU
YES
4
04-FEB-22
FRI
YES
4
04-MAR-22
FRI
YES
4
06-APR-22
WED
YES
4
05-MAY-22
THU
YES
4
06-JUN-22
MON
YES
4
08-JUL-22
FRI
YES
4
04-AUG-22
THU
YES
4
06-SEP-22
TUE
YES
4
06-OCT-22
THU
YES
4
04-NOV-22
FRI
YES
4
06-DEC-22
TUE
YES
4
This dataset now can be used for any scheduling policy that you want. You just have to check if your actual date is listed within or you can use these dates to instruct the scheduler.
Regards...

How to get top 10 data weekly (This week, Previous week, Last month, 2 months ago, 3 month ago)

I want to retrieve the Top 10 Products - weekly
Rank This week product Previous week rank Last month rank 2 month ago rank 3 month ago rank
1 Watch 2 3 1 4
2 Radio 3 2 4 5
3 Pen 4 5 6 7
4
5
6
7
8
9
10
Please help me with how to get this type of data from SQL queries. Thanks
Assuming you have a table:
CREATE TABLE your_table (
product VARCHAR2(20),
some_date_column DATE
)
Then you can use conditional aggregation inside the RANK analytic function:
SELECT product,
RANK() OVER (
ORDER BY COUNT(
CASE
WHEN some_date_column >= TRUNC(SYSDATE, 'IW')
AND some_date_column < TRUNC(SYSDATE, 'IW') + INTERVAL '7' DAY
THEN 1
END
) DESC
) AS rank_this_week,
RANK() OVER (
ORDER BY COUNT(
CASE
WHEN some_date_column >= TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY
AND some_date_column < TRUNC(SYSDATE, 'IW')
THEN 1
END
) DESC
) AS rank_last_week,
RANK() OVER (
ORDER BY COUNT(
CASE
WHEN some_date_column >= ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1)
AND some_date_column < TRUNC(SYSDATE, 'MM')
THEN 1
END
) DESC
) AS rank_last_month,
RANK() OVER (
ORDER BY COUNT(
CASE
WHEN some_date_column >= ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2)
AND some_date_column < ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -1)
THEN 1
END
) DESC
) AS rank_two_month,
RANK() OVER (
ORDER BY COUNT(
CASE
WHEN some_date_column >= ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3)
AND some_date_column < ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -2)
THEN 1
END
) DESC
) AS rank_three_month
FROM your_table
WHERE some_date_column < TRUNC(SYSDATE, 'IW') + INTERVAL '7' DAY
AND some_date_column >= ADD_MONTHS(TRUNC(SYSDATE, 'IW'), -3)
GROUP BY product
ORDER BY rank_this_week
FETCH FIRST 10 ROWS WITH TIES;
Which, for the sample data:
INSERT INTO your_table (product, some_date_column)
SELECT 'A', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 1 UNION ALL
SELECT 'B', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 2 UNION ALL
SELECT 'C', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 3 UNION ALL
SELECT 'D', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 4 UNION ALL
SELECT 'E', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 5 UNION ALL
SELECT 'F', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 6 UNION ALL
SELECT 'G', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 7 UNION ALL
SELECT 'H', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 8 UNION ALL
SELECT 'I', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 9 UNION ALL
SELECT 'J', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 10 UNION ALL
SELECT 'K', TRUNC(SYSDATE, 'IW') FROM DUAL CONNECT BY LEVEL <= 11 UNION ALL
SELECT 'A', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 3 UNION ALL
SELECT 'B', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 3 UNION ALL
SELECT 'C', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 1 UNION ALL
SELECT 'D', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 2 UNION ALL
SELECT 'E', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 5 UNION ALL
SELECT 'F', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 7 UNION ALL
SELECT 'G', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 6 UNION ALL
SELECT 'H', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 4 UNION ALL
SELECT 'I', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 5 UNION ALL
SELECT 'J', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 3 UNION ALL
SELECT 'K', TRUNC(SYSDATE, 'IW') - INTERVAL '7' DAY FROM DUAL CONNECT BY LEVEL <= 2
-- Etc.
(Note: this only has data for the last 2 weeks so all the other ranks will be ties.)
Outputs:
PRODUCT
RANK_THIS_WEEK
RANK_LAST_WEEK
RANK_LAST_MONTH
RANK_TWO_MONTH
RANK_THREE_MONTH
K
1
9
1
1
1
J
2
6
1
1
1
I
3
3
1
1
1
H
4
5
1
1
1
G
5
2
1
1
1
F
6
1
1
1
1
E
7
3
1
1
1
D
8
9
1
1
1
C
9
11
1
1
1
B
10
6
1
1
1
db<>fiddle here

Oracle SQL counting the days of the week of the same month

How can I count the days of each week for a specific month that the user will give to my SQL query? For example, if the user gives April 2021, the result will be:
If the user gives May 2021 the result will be:
Here is a direct computation of the same. The input is given as a string, such as May 2021; you can use a bind variable in its place. Just keep in mind the possibility that the user may be in a non-English-speaking locale; as long as they use their local language in passing the month to the query, everything should work fine.
with
inputs (mth) as (select 'May 2021' from dual)
, first_day (dt) as (select to_date(mth, 'fmMonth yyyy') from inputs)
, mondays (dt, ord, lst) as (
select trunc(dt, 'iw') + 7 * (level - 1), level, max(level) over ()
from first_day
connect by level <= 1 + (trunc(add_months(dt, 1), 'iw') - trunc(dt, 'iw')) / 7
)
select to_number(to_char(dt, 'iw')) as week_number,
case ord when 1 then dt + 7 - trunc(dt + 7, 'mm')
when lst then last_day(dt) + 1 - dt
else 7 end as week_days
from mondays
order by week_number
;
WEEK_NUMBER WEEK_DAYS
----------- ----------
17 2
18 7
19 7
20 7
21 7
22 1
I think this is the query you are looking for:
SELECT WEEK AS WEEK_NUMBER, COUNT(*) AS WEEK_DAYS
FROM (SELECT TO_CHAR(FIRST_DAY + (LEVEL-1), 'IW') AS WEEK
FROM (SELECT supplied_date AS FIRST_DAY, LAST_DAY(supplied_date) - SUPPLIED_DATE+1 AS DAYS
FROM (SELECT TO_DATE('05/2021', 'MM/YYYY') AS SUPPLIED_DATE
FROM DUAL))
CONNECT BY LEVEL <= DAYS)
GROUP BY WEEK
ORDER BY WEEK;
Just replace the inner TO_DATE with your date.
Edit 1: Additional Column (See Comments)
SELECT MONTH_NAME, WEEK AS WEEK_NUMBER, COUNT(*) AS WEEK_DAYS
FROM (SELECT TO_CHAR(FIRST_DAY, 'MONTH') AS MONTH_NAME, TO_CHAR(FIRST_DAY + (LEVEL-1), 'IW') AS WEEK
FROM (SELECT supplied_date AS FIRST_DAY, TO_CHAR(LAST_DAY(supplied_date), 'DD') AS DAYS
FROM (SELECT TO_DATE('05/2021', 'MM/YYYY') AS SUPPLIED_DATE
FROM DUAL))
CONNECT BY LEVEL <= DAYS)
GROUP BY MONTH_NAME, WEEK
ORDER BY WEEK;
Note: I also changed the way I calculate the number of days in the month.
You can generate the weeks (without needing to use any aggregation) using:
WITH input ( month ) AS (
SELECT DATE '2021-04-01' FROM DUAL
),
weeks_of_month ( month_start, week_start, end_day ) AS (
SELECT TRUNC( month, 'MM' ),
TRUNC( month, 'IW' ),
LAST_DAY( TRUNC( month ) )
FROM input
UNION ALL
SELECT month_start,
week_start + INTERVAL '7' DAY,
end_day
FROM weeks_of_month
WHERE week_start + INTERVAL '7' DAY <= end_day
)
SELECT TO_CHAR( week_start, 'IW' ) AS iso_week,
GREATEST( month_start, week_start ) AS first_day_of_week,
LEAST( end_day, week_start + INTERVAL '6' DAY ) AS last_day_of_week,
LEAST( end_day + 1, week_start + INTERVAL '7' DAY )
- GREATEST( month_start, week_start ) AS days
FROM weeks_of_month;
Which outputs (with the NLS_DATE_FORMAT set to YYYY-MM-DD (DY)):
ISO_WEEK
FIRST_DAY_OF_WEEK
LAST_DAY_OF_WEEK
DAYS
13
2021-04-01 (THU)
2021-04-04 (SUN)
4
14
2021-04-05 (MON)
2021-04-11 (SUN)
7
15
2021-04-12 (MON)
2021-04-18 (SUN)
7
16
2021-04-19 (MON)
2021-04-25 (SUN)
7
17
2021-04-26 (MON)
2021-04-30 (FRI)
5
db<>fiddle here

How do i find out the number of days in a previous month in Oracle?

How do i find out the number of days in a previous month in Oracle
You can get the first day of the current month with trunc(sysdate, 'MM'), then subtract a month to get the first day of the previous month; then use last_day() to get the last day of that month; then extract() the day number from that:
select extract(day from last_day(add_months(trunc(sysdate, 'MM'), -1)))
from dual;
EXTRACT(DAYFROMLAST_DAY(ADD_MONTHS(TRUNC(SYSDATE,'MM'),-1)))
------------------------------------------------------------
31
Mostly just for fun, you can see the numbers that gets for say the last six months with a hierarchical query:
select last_day(add_months(trunc(sysdate, 'MM'), - level)) as last_date,
extract(day from last_day(add_months(trunc(sysdate, 'MM'), - level))) as last_day_number
from dual
connect by level <= 6;
LAST_DATE LAST_DAY_NUMBER
---------- ---------------
2019-03-31 31
2019-02-28 28
2019-01-31 31
2018-12-31 31
2018-11-30 30
2018-10-31 31
As #GordonLinoff pointed out, the trunc() call is a bit redundant - because add_months() is quite forgiving - so you can simplify further to:
select extract(day from last_day(add_months(sysdate, -1)))
from dual;
You could also use subtract an interval instead, but then you do need to truncate the current date first, as that won't like dates at the end of the month if the preceding month has fewer days:
select extract(day from last_day(trunc(sysdate, 'MM') - interval '1' month))
from dual;
Are you looking for this?
SELECT 1 + LAST_DAY(ADD_MONTHS(trunc(SYSDATE), -1)) - TRUNC(ADD_MONTHS(SYSDATE, -1), 'MM')
from dual;
31

Number of days, weeks,months,years,quarters since 2000

I need to populate a calendar table in a Oracle 11g database with the following:
calendar_date,
week_number,
week_year,
day_since_2000,
week_since_2000,
month_since_2000,
quarter_since_2000,
week_of_month
The table is already populated with data since 2000 I now need to populate it going back to 1994 with negative numbers for the since_2000 columns. I think I have everything figured but for week since 2000 and quarter since 2000.
EDIT1: Just noticed my week since 200 and month since 2000 is still messed up. Quarter since 2000 looks good after using the answer mentioned below. I am updating the query with the latest.
EDIT2: It was not working because of the missing trunc(). Its working fine now. Latest query updated.
This is what I am using to do that:
/* Formatted on 2/1/2013 11:54:27 AM (QP5 v5.227.12220.39724) */
CREATE OR REPLACE PROCEDURE populate_d_calendar (start_date IN DATE,
end_date IN DATE)
AS
BEGIN
INSERT INTO d_calendar (calendar_date,
week_number,
week_year,
day_since_2000,
week_since_2000,
month_since_2000,
quarter_since_2000,
week_of_month)
SELECT dt, --Date
TO_CHAR (dt,
'ww'), --Week in the year
TO_CHAR (dt,
'yyyy'), --Year
TO_CHAR (dt - end_date), --Day Since 2000
TRUNC (TO_CHAR (dt - end_date) / 7), --Week Since 2000
TRUNC (MONTHS_BETWEEN (dt,
end_date)), --Month Since 2000
CASE
WHEN TO_CHAR (dt,
'MMDD') >= '0101'
AND TO_CHAR (dt,
'MMDD') < '0401'
THEN
0
+ 4
* TRUNC ( MONTHS_BETWEEN (TO_DATE ( '0101'
|| TO_CHAR (dt,
'yyyy'),
'mmddyyyy'),
TO_DATE ('01Jun2000'))
/ 12) --q1
WHEN TO_CHAR (dt,
'MMDD') >= '0401'
AND TO_CHAR (dt,
'MMDD') < '0701'
THEN
1
+ 4
* TRUNC ( MONTHS_BETWEEN (TO_DATE ( '0101'
|| TO_CHAR (dt,
'yyyy'),
'mmddyyyy'),
TO_DATE ('01Jun2000'))
/ 12) --q2
WHEN TO_CHAR (dt,
'MMDD') >= '0701'
AND TO_CHAR (dt,
'MMDD') < '1001'
THEN
2
+ 4
* TRUNC ( MONTHS_BETWEEN (TO_DATE ( '0101'
|| TO_CHAR (dt,
'yyyy'),
'mmddyyyy'),
TO_DATE ('01Jun2000'))
/ 12) --q3
WHEN TO_CHAR (dt,
'MMDD') >= '1001'
AND TO_CHAR (dt,
'MMDD') <= '1231'
THEN
3
+ 4
* TRUNC ( MONTHS_BETWEEN (TO_DATE ( '0101'
|| TO_CHAR (dt,
'yyyy'),
'mmddyyyy'),
TO_DATE ('01Jun2000'))
/ 12) --q4
END
quarters_since_2000, --Quarter Since 2000
TO_CHAR (dt,
'w') --Week of the month
FROM (SELECT start_date + LEVEL - 1 dt
FROM DUAL
CONNECT BY LEVEL <= end_date - start_date + 1);
END;
/
i think you're after a floating point like with the others so maybe:
TO_CHAR (dt - end_date)/7 week_since_2000
and
(MONTHS_BETWEEN (dt,
end_date)/3) quarter_since_2000
with weeks you can follow one of the methods here:
http://searchoracle.techtarget.com/answer/Calculating-weeks-between-two-dates
because it will depend on which rules are more useful to you
with quarters, use this:
case
WHEN TO_CHAR (dt,'MMDD') >= '0101' and TO_CHAR (dt,'MMDD') < '0401' then 0 + 4 * trunc(months_between( to_date('0101' || to_char(dt,'yyyy'),'mmddyyyy'),to_date('01Jun2000' )) /12) --q1
WHEN TO_CHAR (dt,'MMDD') >= '0401' and TO_CHAR (dt,'MMDD') < '0701' then 1 + 4 * trunc(months_between( to_date('0101' || to_char(dt,'yyyy'),'mmddyyyy'),to_date('01Jun2000' )) /12) --q2
WHEN TO_CHAR (dt,'MMDD') >= '0701' and TO_CHAR (dt,'MMDD') < '1001' then 2 + 4 * trunc(months_between( to_date('0101' || to_char(dt,'yyyy'),'mmddyyyy'),to_date('01Jun2000' )) /12) --q3
WHEN TO_CHAR (dt,'MMDD') >= '1001' and TO_CHAR (dt,'MMDD') <= '1231' then 3 + 4 * trunc(months_between( to_date('0101' || to_char(dt,'yyyy'),'mmddyyyy'),to_date('01Jun2000' )) /12) --q4
end quarters_since_2000,
This is my version of calendar table from 1/1/2013 till today. I'm not sure how do you need to insert number of months, quarters, days etc... You need to display total number of months between every year or once? You can add those calc yourself or add desired output in your post to make it clear. See addl queries/comments below:
-- Days,weeks, quarters from 1/1/2013 --
SELECT start_date -- 1/1/2013 --
, TRUNC(start_date, 'iw') wk_starts
, TRUNC(start_date, 'iw') + 7 - 1/86400 wk_ends
, TO_NUMBER (TO_CHAR (start_date, 'IW')) ISO_wk#
, TO_NUMBER (TO_CHAR (start_date, 'Q')) Quarters
FROM
(
SELECT TRUNC(SYSDATE, 'Y')-1 + LEVEL AS start_date
FROM dual
CONNECT BY LEVEL <=
( -- replace this part to go back to 1994 - see below --
SELECT TRUNC(ADD_MONTHS (SYSDATE, 12), 'Y')-TRUNC(SYSDATE, 'Y') "Num of Days in 2013"
FROM dual
)
)
/
START_DATE WK_STARTS WK_ENDS ISO_WK# QUARTERS
---------------------------------------------------------------------
1/1/2013 12/31/2012 1/6/2013 11:59:59 PM 1 1
1/2/2013 12/31/2012 1/6/2013 11:59:59 PM 1 1
......
2/19/2013 2/18/2013 2/24/2013 11:59:59 PM 8 1
2/20/2013 2/18/2013 2/24/2013 11:59:59 PM 8 1
......
3/10/2013 3/4/2013 3/10/2013 11:59:59 PM 10 1
3/11/2013 3/11/2013 3/17/2013 11:59:59 PM 11 1
.......
-- 6971 days from 1/1/1994 till today - 2/1/2013 --
SELECT TRUNC(SYSDATE) - TRUNC(ADD_MONTHS (SYSDATE, -12*19), 'Y') "Num of Days from 1994"
FROM dual
/
-- 4780 days from 1/1/2000 till today - 2/1/2013 --
SELECT TRUNC(SYSDATE) - TRUNC(ADD_MONTHS (SYSDATE, -12*13), 'Y') "Num of Days from 2000"
FROM dual
/
-- 156 Months between from 2000 toll today --
SELECT MONTHS_BETWEEN(TRUNC(SYSDATE), TRUNC(ADD_MONTHS (SYSDATE, -12*13))) mo_btw_2000_till_today
FROM dual
/
-- Number of weeks btw. 2 dates --
SELECT to_char(sysdate, 'WW') - to_char(sysdate-30, 'WW') number_of_weeks FROM dual
/
This may not be exactly what you want... To help you more I need to see the actual expected output of your query. Just trying to help...