How about Table un-nesting
Rajeshwaran Jeyabal, September 04, 2015 - 8:06 am UTC
Instead of reading the table 'test1' three times (twice for aggregation and once for joins) we scan it once and do a Cartesian of needed rows.
rajesh@ORA10G> select * from t;
START_DATE STOP_DATE
----------- -----------
03-jan-2015 15-jan-2015
09-apr-2015 12-jun-2015
15-oct-2015 18-mar-2016
3 rows selected.
rajesh@ORA10G> select *
2 from t ,
3 table( cast( multiset( select level
4 from dual
5 connect by level <= months_between(trunc(stop_date,'mm'),
6 trunc(start_date,'mm')) + 1 )
7 as sys.odcinumberlist) ) ;
START_DATE STOP_DATE COLUMN_VALUE
----------- ----------- ------------
03-jan-2015 15-jan-2015 1
09-apr-2015 12-jun-2015 1
09-apr-2015 12-jun-2015 2
09-apr-2015 12-jun-2015 3
15-oct-2015 18-mar-2016 1
15-oct-2015 18-mar-2016 2
15-oct-2015 18-mar-2016 3
15-oct-2015 18-mar-2016 4
15-oct-2015 18-mar-2016 5
15-oct-2015 18-mar-2016 6
10 rows selected.
rajesh@ORA10G>
rajesh@ORA10G> select add_months( trunc(start_date,'mm'),column_value-1)
2 from t ,
3 table( cast( multiset( select level
4 from dual
5 connect by level <= months_between(trunc(stop_date,'mm'),
6 trunc(start_date,'mm')) + 1 )
7 as sys.odcinumberlist) ) ;
ADD_MONTHS(
-----------
01-jan-2015
01-apr-2015
01-may-2015
01-jun-2015
01-oct-2015
01-nov-2015
01-dec-2015
01-jan-2016
01-feb-2016
01-mar-2016
10 rows selected.
rajesh@ORA10G>
James Su, September 04, 2015 - 8:21 pm UTC
What if there's overlap between the rows? I assume you want the ranges separately. You will need a key to identify these rows.
CREATE TABLE TEST1 AS (SELECT 1 AS ID,SYSDATE AS START_DATE, SYSDATE AS STOP_DATE FROM DUAL WHERE 1 = 2);
INSERT INTO TEST1 (ID,START_DATE, STOP_DATE) VALUES (1,to_date('01032015','MMDDYYYY'),to_date('01152015','MMDDYYYY') );
INSERT INTO TEST1 (ID,START_DATE, STOP_DATE) VALUES (2,to_date('04092015','MMDDYYYY'),to_date('06122015','MMDDYYYY') );
INSERT INTO TEST1 (ID,START_DATE, STOP_DATE) VALUES (3,to_date('10152015','MMDDYYYY'),to_date('03182016','MMDDYYYY') );
select id,to_char(add_months(start_date,level-1),'yyyymm')
from test1
connect by id=prior id and level<=months_between(trunc(stop_date,'mm'),trunc(start_date,'mm'))+1
and prior sys_guid() is not null;