In Oracle 11g and below, you can use a nested table to do this:
with t (dt) as (
select to_date('01/12/2016','dd/mm/yyyy') from dual union all
select to_date('05/07/2016','dd/mm/yyyy') from dual
)
select
t.dt + (x.column_value - 1) * 30 start_date,
t.dt + x.column_value * 30 - 1 end_date,
x.column_value - 1 period_id
from t cross join table(cast(
multiset(
select level
from dual
connect by t.dt + 30 * (level - 1) <= sysdate
) as sys.odcinumberlist
)) x;
Oracle 12c +, OUTER APPLY, :
with t (dt) as (
select to_date('01/12/2016','dd/mm/yyyy') from dual union all
select to_date('05/07/2016','dd/mm/yyyy') from dual
)
select
t.dt + (x.n - 1) * 30 start_date,
t.dt + x.n * 30 - 1 end_date,
x.n - 1 period_id
from t outer apply (
select level n
from dual
connect by t.dt + 30 * (level - 1) <= sysdate
) x;
:
+------------+-----------+-----------+
| START_DATE | END_DATE | PERIOD_ID |
+------------+-----------+-----------+
| 01-DEC-16 | 30-DEC-16 | 0 |
+------------+-----------+-----------+
| 31-DEC-16 | 29-JAN-17 | 1 |
+------------+-----------+-----------+
| 30-JAN-17 | 28-FEB-17 | 2 |
+------------+-----------+-----------+
| 05-JUL-16 | 03-AUG-16 | 0 |
+------------+-----------+-----------+
| 04-AUG-16 | 02-SEP-16 | 1 |
+------------+-----------+-----------+
| 03-SEP-16 | 02-OCT-16 | 2 |
+------------+-----------+-----------+
| 03-OCT-16 | 01-NOV-16 | 3 |
+------------+-----------+-----------+
| 02-NOV-16 | 01-DEC-16 | 4 |
+------------+-----------+-----------+
| 02-DEC-16 | 31-DEC-16 | 5 |
+------------+-----------+-----------+
| 01-JAN-17 | 30-JAN-17 | 6 |
+------------+-----------+-----------+
| 31-JAN-17 | 01-MAR-17 | 7 |
+------------+-----------+-----------+
, CONNECT BY:
select level n
from dual
connect by t.dt + 30 * (level - 1) <= sysdate
CTE - :
with t (dt) as (
select to_date('01/12/2016','dd/mm/yyyy') from dual union all
select to_date('05/07/2016','dd/mm/yyyy') from dual
)