List all the months using oracle sql - 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

Related

Oracle - get previous, current and next year from query [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
Is below example good solution for get previous, current and next year?
with cte as(
Select extract(year from sysdate - 365) as year from dual
union all
Select extract(year from sysdate) as year from dual
union all
Select extract(year from sysdate + 365) as year from dual
)
Select * from cte
YEAR
-----
2020
2021
2022
Or any better solution?
I might overlook something but why not just this?
with cte as(
Select extract(year from sysdate) - 1 as year from dual
union all
Select extract(year from sysdate) as year from dual
union all
Select extract(year from sysdate) + 1 as year from dual
)
Select * from cte
Well, yours isn't correct for e.g. leap years on the last day of that year. Look at 2020:
SQL> select
2 extract(year from to_date('31.12.2020', 'dd.mm.yyyy') - 365) result
3 from dual;
RESULT
----------
2020
SQL>
See? Turns out that "previous" year for date 31.12.2020 is still 2020.
ADD_MONTHS is safer, I guess:
SQL> select
2 extract (year from add_months(to_date('31.12.2020', 'dd.mm.yyyy'), -12)) result
3 from dual;
RESULT
----------
2019
SQL>
SQL> select
2 extract (year from add_months(trunc(sysdate), -12)) previous,
3 extract (year from add_months(trunc(sysdate), 0)) this,
4 extract (year from add_months(trunc(sysdate), 12)) next
5 from dual;
PREVIOUS THIS NEXT
---------- ---------- ----------
2020 2021 2022
SQL>
(this, of course, doesn't require add_months, but I kept it to make query look prettier).
Or, why not simply
SQL> select this - 1 as previous,
2 this,
3 this + 1 as next
4 from (select extract(year from sysdate) as this from dual);
PREVIOUS THIS NEXT
---------- ---------- ----------
2020 2021 2022
SQL>
For 3 rows, use a CTE:
SQL> with temp (this) as
2 (select extract(year from sysdate) from dual)
3 select this - 1 as year from temp union all
4 select this from temp union all
5 select this + 1 from temp;
YEAR
----------
2020
2021
2022
SQL>

Oracle SQL: loop through year

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

Need SQL to generate multiple rows from subquery

I have a query that selects a month and year from a complex heirachy of tables. To simplify this question, we can use this query:
select 2 as month, 2018 as year from dual;
I need SQL that will use that query as a subquery to output 3 row: that month as well as with the preceeding 2 months (including years). So the output needed for that specific case would be:
Month Year
2 2018
1 2018
12 2017
I have no idea how to proceed. Ideas anyone?
If you have the month/year already in a DATE column, it would be one less conversion, but if they are separate columns like you have provided, you can use a query like the one below.
Query
WITH sample_data AS (SELECT 2 AS month, 2018 AS year FROM DUAL)
SELECT TO_CHAR (ADD_MONTHS (TO_DATE (month || '-' || year, 'MM-YYYY'), ((LEVEL * -1) + 1)), 'MM')
AS month,
TO_CHAR (ADD_MONTHS (TO_DATE (month || '-' || year, 'MM-YYYY'), ((LEVEL * -1) + 1)), 'YYYY')
AS year
FROM sample_data
CONNECT BY LEVEL <= 3;
Result
MONTH YEAR
________ _______
02 2018
01 2018
12 2017
For Oracle 12+:
select *
from
(select 2 as month, 2018 as year
from dual) complex_query
,lateral(
select
extract(month from add_months(dt, 1-level)) as month,
extract(year from add_months(dt, 1-level)) as year
from (
select
to_date(complex_query.year||'-'||complex_query.month||'-01', 'yyyy-mm-dd') as dt
from dual
)
connect by level<=3
);
For previous versions:
select
complex_query.*
,extract(year from (to_date(year||'-'||month,'yyyy-mm')-delta)) year_2
,extract(month from (to_date(year||'-'||month,'yyyy-mm')-delta)) month_2
from
(select 2 as month, 2018 as year
from dual) complex_query
,(select
NUMTOYMINTERVAL(level-1,'month') delta
from dual
connect by level<=3
) v
Results:
MONTH YEAR YEAR_2 MONTH_2
---------- ---------- ---------- ----------
2 2018 2018 1
2 2018 2017 12
2 2018 2017 11
Would union work?
with primary_month as (
select 2 as month, 2018 as year from dual
)
select (case when month = 1 then 13 else month end) - 1 as month , case when month = 1 then year-1 else year end as year from primary_month
union
select month, year from primary_month
union
select month + 1 as month, year from primary_month
;
This example won't handle boundary cases like if the primary month is January, since there is no month 0, but I'm not sure if that's what you're going for and it depends on the real query and schema (e.g. are you using timestamp columns?)

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>

Generate 3 years

Tying to generate 3 years of data as below
31-DEC-17
31-DEC-18
31-DEC-19
below query generates 3 months. How do i transfer this to 3 years
select LAST_DAY(add_months(date '2017-01-01', level - 1)) as mth
from dual
connect by level <= 3
Multiply parameter by 12:
select last_day(add_months(date '2017-01-01', (level - 1) * 12 )) as mth
from dual
connect by level <= 3
demo
use <=36 which will generate till 31-DEC-19
select LAST_DAY(add_months(date '2017-01-01', level - 1)) as mth
from dual
connect by level <= 36
As #APC mentions, last_day function depends on your NLS Date Settings. So, you may prefer truncate function truncated to the unit specified by yyyy as below instead :
select add_months(trunc(date'2017-01-01','yyyy'), level * 12 ) - 1
as "Last Days"
from dual
connect by level <= 3;
Last Days
----------
2017-12-31
2018-12-31
2019-12-31
Demo