Oracle SQL: loop through year - sql

I need to run this query to get 5 years data (2015 to 2019), and I am wondering if there is a way to automatically loop through year, instead of manually changing the year (e.g., from 2015 to 2016) and running this query 5 times? Any help will be appreciated! Thanks!
Select ID,program, open_date, close_date
From clients
Where open_date=to_date('01/01/2015','mm/dd/yyyy')
and close_date=to_date('12/31/2015','mm/dd/yyyy')

You can always generate calendar you need and join it with your query.
with cal as (
select add_months(date '2015-01-01', (level - 1)*12) as start_dt,
add_months(date '2015-12-31', (level - 1)*12) as end_dt
from dual
connect by level <= 5
)
Select c.ID, c.program, c.open_date, c.close_date
From clients c
join cal
on c.open_date=cal.start_dt and c.close_date=cal.end_dt

Row generator it is. For example:
SQL> with period (start_year, end_year) as
2 (select 2015, 2020 from dual)
3 select d.dummy, p.start_year + level - 1 as year
4 from dual d cross join period p
5 connect by level <= end_year - start_year
6 order by year;
D YEAR
- ----------
X 2015
X 2016
X 2017
X 2018
X 2019
SQL>
Applied to your code (can't test it, don't have your tables):
with
period (start_year, end_year) as
(select 2015, 2020 from dual),
select c.id, c.program, c.open_date, c.close_date
from clients c cross join period p
where open_date = add_months(trunc(to_date(p.start_year, 'yyyy'), 'yyyy'), 12 * (level - 1))
and close_date = add_months(trunc(to_date(p.start_year, 'yyyy'), 'yyyy'), 12 * (level )) - 1
connect by level <= p.end_year - p.start_year;
because those values produce
SQL> with
2 period (start_year, end_year) as
3 (select 2015, 2020 from dual)
4 select add_months(trunc(to_date(p.start_year, 'yyyy'), 'yyyy'), 12 * (level - 1)) a,
5 add_months(trunc(to_date(p.start_year, 'yyyy'), 'yyyy'), 12 * (level )) - 1 b
6 from period p
7 connect by level <= end_year - start_year;
A B
---------- ----------
01.01.2015 31.12.2015
01.01.2016 31.12.2016
01.01.2017 31.12.2017
01.01.2018 31.12.2018
01.01.2019 31.12.2019
SQL>

Take a look at the following code snippet:
SELECT EXTRACT(YEAR FROM TO_DATE('01.01.2015', 'dd.mm.yyyy')) + ROWNUM - 1 AS "YEAR"
FROM dual
CONNECT BY ROWNUM <= 5

Related

Get count days in current year by day name or day id

name id
----------------
Mon 1
Thu 2
Wen 3
Thr 4
Fri 5
Sat 6
San 7
How get count day where id in eg. (1,2,3,4) and year is 2021
The result should be 208.
Actually, it is 208 for year 2021.
SQL> WITH
2 year AS (SELECT &par_year year FROM DUAL),
3 calendar
4 AS
5 ( SELECT TRUNC (TO_DATE (y.year, 'yyyy'), 'yyyy') + LEVEL - 1 datum
6 FROM year y
7 CONNECT BY LEVEL <=
8 ADD_MONTHS (TRUNC (TO_DATE (y.year, 'yyyy'), 'yyyy'), 12)
9 - TRUNC (TO_DATE (y.year, 'yyyy'), 'yyyy'))
10 SELECT SUM (CASE
11 WHEN TO_NUMBER (TO_CHAR (c.datum, 'd')) IN (1,
12 2,
13 3,
14 4)
15 THEN
16 1
17 ELSE
18 0
19 END) result
20 FROM calendar c;
Enter value for par_year: 2021
RESULT
----------
208
SQL> /
Enter value for par_year: 2020
RESULT
----------
210
SQL>
What does it do?
YEAR CTE contains year you're interested in
CALENDAR CTE creates all dates in that particular year
SUM function conditionally adds 1 if TO_CHAR(datum, 'd') is 1, 2, 3 or 4
that's all

Problem with getting the quarter from a date in Oracle

I've written a query to get the start date of the quarters from current year and previous year by using the sysdate.
eg. Today falls in the 1st quarter of the year, therefore I only want to get the start date of 1st quarter of last year and this year.
If I'm on December (which is in the 4th quarter), I want to get the start dates of 8 quarters (4 from last year, 4 from this year.)
select b.dt,
to_number(to_char(SYSDATE, 'Q')),
to_number(to_char(b.dt, 'Q'))
from dual a,
(select add_months(trunc(ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -12),
'yyyy'),
(rownum - 1) * 3) dt
from all_objects
where rownum <= 8
and add_months(trunc(ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -12),
'yyyy'),
(rownum - 1) * 3) <= SYSDATE
and to_number(to_char(SYSDATE, 'Q')) >=
to_number(to_char(add_months(trunc(ADD_MONTHS(TRUNC(SYSDATE,
'MM'),
-12),
'yyyy'),
(rownum - 1) * 3),
'Q'))) b
This query only returns the start date of 1st quarter of last year. I expect to get the start date of the 1st quarter of this year as well.
Here's one option; see comments within the code.
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> with
2 -- this mimics SYSDATE
3 today (datum) as
4 (select date '&date_literal' from dual),
5 -- which quarter does DATUM belong to? Find 1st day in "this" and "previous" year
6 quart as
7 (select trunc(datum, 'yyyy') this,
8 trunc(add_months(datum, -12), 'yyyy') previous,
9 to_char(datum, 'q') quart from today)
10 -- the fina result
11 select add_months(this, (level - 1) * 3) result
12 from quart
13 connect by level <= quart
14 union all
15 select add_months(previous, (level - 1) * 3) result
16 from quart
17 connect by level <= quart;
Enter value for date_literal: 2019-03-24
RESULT
----------
01.01.2019
01.01.2018
SQL> /
Enter value for date_literal: 2019-08-13
RESULT
----------
01.01.2019
01.04.2019
01.07.2019
01.01.2018
01.04.2018
01.07.2018
6 rows selected.
SQL>

How can I generate 4-week ranges of dates?

I have to generate date range for 1 year in gap of 4 weeks ( or 28 days ) from a fixed date backward and going forward. For example I have DATE '2016-02-20'. I need to generate the below.
Start date = Sunday , End-date = Saturday
No Start_date End_date
==== ========= =======
1 1/24/2016 2/20/2016
2 12/27/2015 1/23/2016
3 11/29/2015 12/26/2015
4 .....
13 2/22/2015 3/21/2015
14 1/25/2015 2/21/2015
But,when 03/20/2016(Sunday) comes,it should add
1. 2/21/2016 3/19/2016 & remove 14. 1/25/2015 2/21/2015
and so on after every 4 weeks.
I have written the below, but I need help to iterate in minimal code( if possible.)
SELECT LEVEL,
DATE '2016-02-20'-27*LEVEL-LEVEL+1 AS start_date,
DATE '2016-02-20'-28*(LEVEL-1) AS end_date
FROM DUAL
Connect BY LEVEL < 15;
It seems you want to have a rolling window of a year's worth of four-week ranges, based from the current date. To do that you need a fixed known period start (or end) date you can work from. Picking one that happens to be January 1st you can do:
SELECT DATE '2012-01-01' + (28 * (LEVEL - 1)) AS start_date,
DATE '2012-01-01' + (28 * LEVEL) - 1 AS end_date
FROM DUAL
CONNECT BY DATE '2012-01-01' + (28 * LEVEL) - 1 <= TRUNC(sysdate)
Which will find 54 periods up to today. On March 21st it will find 55 periods, etc. You only want those that are in the last year, so use that as an inline view and restrict the range:
SELECT ROW_NUMBER() OVER (ORDER BY start_date DESC) AS no, start_date, end_date
FROM (
SELECT DATE '2012-01-01' + (28 * (LEVEL - 1)) AS start_date,
DATE '2012-01-01' + (28 * LEVEL) - 1 AS end_date
FROM DUAL
CONNECT BY DATE '2012-01-01' + (28 * LEVEL) - 1 <= TRUNC(sysdate)
)
WHERE end_date >= ADD_MONTHS(TRUNC(sysdate), -12)
ORDER BY start_date DESC;
NO START_DATE END_DATE
---------- ---------- ----------
1 01/24/2016 02/20/2016
2 12/27/2015 01/23/2016
3 11/29/2015 12/26/2015
...
11 04/19/2015 05/16/2015
12 03/22/2015 04/18/2015
13 02/22/2015 03/21/2015
The ROW_NUMBER() just generates your NO column, as the LEVEL is now in the wrong order.
If you always want exactly 14 rows in the result set you can move the ROW_NUMBER() into the inline view:
SELECT no, start_date, end_date
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY LEVEL DESC) AS no,
DATE '2012-01-01' + (28 * (LEVEL - 1)) AS start_date,
DATE '2012-01-01' + (28 * LEVEL) - 1 AS end_date
FROM DUAL
CONNECT BY DATE '2012-01-01' + (28 * LEVEL) - 1 <= TRUNC(sysdate)
)
WHERE no <= 14
ORDER BY no;
NO START_DATE END_DATE
---------- ---------- ----------
1 01/24/2016 02/20/2016
2 12/27/2015 01/23/2016
3 11/29/2015 12/26/2015
...
12 03/22/2015 04/18/2015
13 02/22/2015 03/21/2015
14 01/25/2015 02/21/2015
14 rows selected

Date and quarter SQL ORACLE

I am currently working on oracle sql and have some issues managing dates and quarters.
The first thing I try to do is given a quarter and a year I would like to know the number of days of the quarter. For example, quarter 1 in 2013 had 90 days but in 2012 had 91 days.
The second thing I would like to do is convert a date dd/qq/yyyy to a date
dd/mm/yyyy.
For instance, 60/2/2013 gives 30/5/2013. I am a beginner in Oracle so any help or function names will be highly appreciated.
Thanks
this gives the number of days in the current quarter, playing around with the add_months should allow you to find the length of other quarters
select (add_months(trunc(sysdate,'q'),3) - 1) - trunc(sysdate,'q')
from dual;
For your first question, hopefully this will give you some idea of what to do:
with sample_data as (select 2012 yr, 1 quarter from dual union all
select 2012 yr, 2 quarter from dual union all
select 2012 yr, 3 quarter from dual union all
select 2012 yr, 4 quarter from dual union all
select 2013 yr, 1 quarter from dual union all
select 2013 yr, 2 quarter from dual)
---- end of mimicking a table called "sample_data"; see query below:
select yr,
quarter,
add_months(to_date('01/01/'||yr, 'dd/mm/yyyy'), (quarter - 1)*3) qtr_st,
add_months(to_date('01/01/'||yr, 'dd/mm/yyyy'), quarter * 3) - 1 qtr_end,
add_months(to_date('01/01/'||yr, 'dd/mm/yyyy'), quarter * 3) - add_months(to_date('01/01/'||yr, 'dd/mm/yyyy'), (quarter - 1)*3) diff
from sample_data;
YR QUARTER QTR_ST QTR_END DIFF
---------- ---------- ---------- ---------- ----------
2012 1 01/01/2012 31/03/2012 91
2012 2 01/04/2012 30/06/2012 91
2012 3 01/07/2012 30/09/2012 92
2012 4 01/10/2012 31/12/2012 92
2013 1 01/01/2013 31/03/2013 90
2013 2 01/04/2013 30/06/2013 91
N.B. Because you're including the day of the start_date in the count, the difference is effectively how many days between the 1st of the quarter and the 1st of the next quarter, or qtr_end - qtr_st + 1 from my query above.
For your second question, here's one way:
with sample_data as (select '60/2/2013' dy_qtr_fmt from dual union all
select '60/02/2013' dy_qtr_fmt from dual union all
select '01/1/2013' dy_qtr_fmt from dual union all
select '1/1/2013' dy_qtr_fmt from dual)
---- end of mimicking a table called "sample_data"; see query below:
select dy_qtr_fmt,
add_months(year_st, (qtr-1)*3) + num_days_in_qtr - 1 dt
from (select dy_qtr_fmt,
to_date('01/01/'||substr(dy_qtr_fmt, -4), 'dd/mm/yyyy') year_st,
to_number(substr(dy_qtr_fmt, instr(dy_qtr_fmt, '/', 1, 1) + 1, instr(dy_qtr_fmt, '/', 1, 2) - instr(dy_qtr_fmt, '/', 1, 1) -1)) qtr,
to_number(substr(dy_qtr_fmt, 1, instr(dy_qtr_fmt, '/', 1, 1) - 1)) num_days_in_qtr
from sample_data);
DY_QTR_FMT DT
---------- ----------
60/2/2013 30/05/2013
60/02/2013 30/05/2013
01/1/2013 01/01/2013
1/1/2013 01/01/2013

List all the months using oracle sql

Guys, is there any better way to list all the months other than this:
select to_char(add_months(to_date('01/01/1000', 'DD/MM/RRRR'), ind.l-1), 'MONTH') as month_descr,
ind.l as month_ind
from dual descr,
(select l
from (select level l
from dual
connect by level <= 12
)
) ind
order by 2;
ANSWER:
SELECT to_char(add_months(SYSDATE, (LEVEL-1 )),'MONTH') as months
FROM dual
CONNECT BY LEVEL <= 1
ONE MORE QUESTION SEE BELOW
Also I want to list the previous two years including the current year. I wrote this sql query. Let me know if there is anything better.
select extract(year from sysdate) - (level-1) as years
from dual
connect by level <=3
order by years
Not better, but just a bit cleaner:
SQL> select to_char(date '2000-12-01' + numtoyminterval(level,'month'),'MONTH') as month
2 from dual
3 connect by level <= 12
4 /
MONTH
---------
JANUARY
FEBRUARY
MARCH
APRIL
MAY
JUNE
JULY
AUGUST
SEPTEMBER
OCTOBER
NOVEMBER
DECEMBER
12 rows selected.
Regards,
Rob.
Yup.
1:
SELECT * FROM WWV_FLOW_MONTHS_MONTH;
2: (UPD:)
WITH MONTH_COUNTER AS (
SELECT LEVEL-1 AS ID
FROM DUAL
CONNECT BY LEVEL <= 12
)
SELECT TO_CHAR(ADD_MONTHS(TO_DATE('01/01/1000', 'DD/MM/RRRR'), ID),'MONTH') FROM MONTH_COUNTER;
select to_char(add_months(trunc(sysdate, 'yyyy'), level - 1), 'MONTH') months
from dual
connect by level <= 12;
Returns:
MONTHS
--------------------
JANUARY
FEBRUARY
MARCH
APRIL
MAY
JUNE
JULY
AUGUST
SEPTEMBER
OCTOBER
NOVEMBER
DECEMBER
12 rows selected.
SELECT to_char(to_date( level,'mm'), 'MONTH') Months FROM DUAL CONNECT BY LEVEL <=12;
Regards,
Prasant Sutaria
SELECT TO_CHAR(TO_DATE(rownum||'-'||rownum||'-'||'2013', 'DD-MM-YYYY'), 'Month')
FROM all_objects
WHERE rownum < 13