Jumroo,
To produce more rows of output than exist in your source table, it is often useful to use some "dummy table" with plenty of rows to actually
seed the query with as many rows as you want to produce.
For the sake of conceptual simplicity, I choose as my driving "dummy table" one that I know exists in every Oracle database: "ALL_TAB_COLUMNS". The only thing that I use from "ALL_TAB_COLUMNS" is row numbers. In your case, I want printed rows for each 30-day period between your "service_start_date" and your "service_end_date" values for a row.
Since Oracle cannot anticipate how many result rows you need for each source row (i.e., one row for each 30-day period between a row's "service_start_date" and "service_end_date"), we must query enough rows from "ALL_TAB_COLUMNS" to accommodate the largest number of rows our data prescribes, yet we do not want to degrade performance by reading
all rows from "ALL_TAB_COLUMNS" (since each Oracle database usually contains tens of thousands of rows in it "ALL_TAB_COLUMNS"). Therefore, In the code, below, I arbitrarily set a limit of 120 (i.e., roughly ten-years worth of) rows to be available to drive your query. If you need more rows or fewer rows, you can easily adjust the 120 to a more appropriate value.
Also, in the code, below, I added an extra column that you did not specify, "Service Step within Batch", which identifies the "month-step" of the row within the current batch. You are certainly welcome to remove that if you wish...I just put it there for your benefit.
I also added more test rows to illustrate:[ul][li]a "multi-year batch" and[/li][li]a batch lasting less than 30 days[/li][/ul]
Here are data and code to do what you wanted:
Code:
select * from services;
BATCH_ID SERVICE_S SERVICE_E
---------- --------- ---------
99999 15-FEB-08 25-APR-08
11111 22-JAN-06 04-FEB-08
22222 12-JAN-08 14-JAN-08
col month_num heading "Service|Step|within|Batch" format 999
col service_start_date heading "Service|Start|Date"
col service_end_date heading "Service|End|Date"
select month_num
,x.batch_id
,x.service_start_date+decode(month_num,1,0,(30*(month_num-1))+1) service_start_date
,least(x.service_start_date+(30*(month_num)),x.service_end_date) service_end_date
from services x
,(select rownum month_num from all_tab_columns where rownum <= 120)
where month_num <= ceil(months_between(service_end_date,service_start_date))
order by batch_id,month_num
/
Service
Step Service Service
within Start End
Batch BATCH_ID Date Date
------- ---------- --------- ---------
1 11111 22-JAN-06 21-FEB-06
2 11111 22-FEB-06 23-MAR-06
3 11111 24-MAR-06 22-APR-06
4 11111 23-APR-06 22-MAY-06
5 11111 23-MAY-06 21-JUN-06
6 11111 22-JUN-06 21-JUL-06
7 11111 22-JUL-06 20-AUG-06
8 11111 21-AUG-06 19-SEP-06
9 11111 20-SEP-06 19-OCT-06
10 11111 20-OCT-06 18-NOV-06
11 11111 19-NOV-06 18-DEC-06
12 11111 19-DEC-06 17-JAN-07
13 11111 18-JAN-07 16-FEB-07
14 11111 17-FEB-07 18-MAR-07
15 11111 19-MAR-07 17-APR-07
16 11111 18-APR-07 17-MAY-07
17 11111 18-MAY-07 16-JUN-07
18 11111 17-JUN-07 16-JUL-07
19 11111 17-JUL-07 15-AUG-07
20 11111 16-AUG-07 14-SEP-07
21 11111 15-SEP-07 14-OCT-07
22 11111 15-OCT-07 13-NOV-07
23 11111 14-NOV-07 13-DEC-07
24 11111 14-DEC-07 12-JAN-08
25 11111 13-JAN-08 04-FEB-08
1 22222 12-JAN-08 14-JAN-08
1 99999 15-FEB-08 16-MAR-08
2 99999 17-MAR-08 15-APR-08
3 99999 16-APR-08 25-APR-08
Let us know if you have questions about any of the code.
![[santa] [santa] [santa]](/data/assets/smilies/santa.gif)
Mufasa
(aka Dave of Sandy, Utah, USA)
[I provide low-cost, remote Database Administration services:
www.dasages.com]