简体   繁体   中英

how to get different date ranges for the last One year as per sysdate

I have a scenario: as per my sysdate i need to capture last 12 months dates.

Example: I will be getting a parameter which is numeric like : 2,3,4,6 ..

If the parameter is 3: then as per sysdate-12 i am expecting 4 records as below

Start_Date  End_Date
20180801    20181101
20181101    20190201
20190201    20190501
20190501    20190827

select TO_CHAR(add_months(trunc(sysdate, 'month'), -12),'YYYYMMDD') Start_Date,TO_CHAR(add_months(trunc(sysdate, 'month'), -9),'YYYYMMDD') End_Date from dual 
union all 
select TO_CHAR(add_months(trunc(sysdate, 'month'), -9),'YYYYMMDD') Start_Date,TO_CHAR(add_months(trunc(sysdate, 'month'), -6),'YYYYMMDD') End_Date from dual 
union all 
select TO_CHAR(add_months(trunc(sysdate, 'month'), -6),'YYYYMMDD') Start_Date,TO_CHAR(add_months(trunc(sysdate, 'month'), -3),'YYYYMMDD') End_Date from dual 
union all 
select TO_CHAR(add_months(trunc(sysdate, 'month'), -3),'YYYYMMDD') Start_Date,TO_CHAR(trunc(sysdate),'YYYYMMDD') End_Date from dual

Between two dates i have difference of 3 months. If the parameter is 2 then difference between Start_Date and End_Date should be 2 months which means i will be getting 6 records.

Can we write a query to read this numeric parameter and create records on the base of the parameter. Without writing multiple queries like above , is there any possibility i can read the parameter and create records

You can use the following query:

SELECT
    ADD_MONTHS(START_,(LEVEL - 1) * &&INPUT_NUMBER) AS START_DATE,
    CASE
        WHEN LEVEL = 12 / ( &&INPUT_NUMBER ) THEN SYSDATE
        ELSE ADD_MONTHS(START_,(LEVEL) * &&INPUT_NUMBER)
    END AS END_DATE
FROM
    (
        SELECT
            ADD_MONTHS(TRUNC(SYSDATE, 'MONTH'), - 12) START_
        FROM
            DUAL
    )
CONNECT BY
    LEVEL <= 12 / ( &&INPUT_NUMBER );

-- With Input parameter as 2

SQL> SELECT
  2      ADD_MONTHS(START_,(LEVEL - 1) * &&INPUT_NUMBER) AS START_DATE,
  3      CASE
  4          WHEN LEVEL = 12 / ( &&INPUT_NUMBER ) THEN SYSDATE
  5          ELSE ADD_MONTHS(START_,(LEVEL) * &&INPUT_NUMBER)
  6      END AS END_DATE
  7  FROM
  8      (
  9          SELECT
 10              ADD_MONTHS(TRUNC(SYSDATE, 'MONTH'), - 12) START_
 11          FROM
 12              DUAL
 13      )
 14  CONNECT BY
 15      LEVEL <= 12 / ( &&INPUT_NUMBER )
 16  ;


START_DAT END_DATE
--------- ---------
01-AUG-18 01-OCT-18
01-OCT-18 01-DEC-18
01-DEC-18 01-FEB-19
01-FEB-19 01-APR-19
01-APR-19 01-JUN-19
01-JUN-19 27-AUG-19

6 rows selected.

SQL>

-- With Input parameter as 3

SQL> SELECT
  2      ADD_MONTHS(START_,(LEVEL - 1) * &&INPUT_NUMBER) AS START_DATE,
  3      CASE
  4          WHEN LEVEL = 12 / ( &&INPUT_NUMBER ) THEN SYSDATE
  5          ELSE ADD_MONTHS(START_,(LEVEL) * &&INPUT_NUMBER)
  6      END AS END_DATE
  7  FROM
  8      (
  9          SELECT
 10              ADD_MONTHS(TRUNC(SYSDATE, 'MONTH'), - 12) START_
 11          FROM
 12              DUAL
 13      )
 14  CONNECT BY
 15      LEVEL <= 12 / ( &&INPUT_NUMBER )
 16  ;
Enter value for input_number: 3


START_DAT END_DATE
--------- ---------
01-AUG-18 01-NOV-18
01-NOV-18 01-FEB-19
01-FEB-19 01-MAY-19
01-MAY-19 27-AUG-19

SQL>

Cheers!!

Basically the same idea as @Tejash, using a hierarchical query but with a bind variable instead of a substitution variable, and counting backwards instead of forwards:

var your_var number;
exec :your_var := 3;

select
  add_months(trunc(sysdate, 'MM'), -(level) * :your_var) as period_start,
  case when level = 1 then trunc(sysdate, 'DD' )
       else add_months(trunc(sysdate, 'MM'), -(level - 1) * :your_var)
  end as period_end
from dual
connect by level <= 12/:your_var
order by period_start;

PERIOD_STA PERIOD_END
---------- ----------
2018-08-01 2018-11-01
2018-11-01 2019-02-01
2019-02-01 2019-05-01
2019-05-01 2019-08-27
exec :your_var := 2;

...

PERIOD_STA PERIOD_END
---------- ----------
2018-08-01 2018-10-01
2018-10-01 2018-12-01
2018-12-01 2019-02-01
2019-02-01 2019-04-01
2019-04-01 2019-06-01
2019-06-01 2019-08-27

But you could also do this with recursive subquery factoring:

exec :your_var := 3;

with rcte (period_start, period_end, final_end) as (
  select add_months(trunc(sysdate, 'MM'), -:your_var),
    trunc(sysdate, 'DD'),
    add_months(trunc(sysdate, 'MM'), -12)
  from dual
  union all
  select add_months(period_start, -:your_var),
    add_months(trunc(period_end, 'MM'), -:your_var),
    final_end
  from rcte
  where period_start > final_end
)
select period_start, period_end
from rcte
order by period_start;

PERIOD_STA PERIOD_END
---------- ----------
2018-08-01 2018-11-01
2018-11-01 2019-02-01
2019-02-01 2019-05-01
2019-05-01 2019-08-27
exec :your_var := 2;

...

PERIOD_STA PERIOD_END
---------- ----------
2018-08-01 2018-10-01
2018-10-01 2018-12-01
2018-12-01 2019-02-01
2019-02-01 2019-04-01
2019-04-01 2019-06-01
2019-06-01 2019-08-27

Or with intervals:

with rcte (period_start, period_end, final_end) as (
  select trunc(sysdate, 'MM') -:your_var * interval '1' month,
    trunc(sysdate, 'DD'),
    trunc(sysdate, 'MM') - interval '1' year
  from dual
  union all
  select period_start -:your_var * interval '1' month,
    trunc(period_end, 'MM') -:your_var * interval '1' month,
    final_end
  from rcte
  where period_start > final_end
)
select period_start, period_end
from rcte
order by period_start;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM