in 10g/11g puoi usare la clausola modello per questo.
SQL> with emps as (select rownum id, name, start_date,
2 end_date, trunc(end_date)-trunc(start_date) date_range
3 from table1)
4 select name, the_date
5 from emps
6 model partition by(id as key)
7 dimension by(0 as f)
8 measures(name, start_date, cast(null as date) the_date, date_range)
9 rules (the_date [for f from 0 to date_range[0] increment 1] = start_date[0] + cv(f),
10 name[any] = name[0]);
NAME THE_DATE
----------- ----------
DAVID SMITH 01-01-2001
DAVID SMITH 01-02-2001
DAVID SMITH 01-03-2001
DAVID SMITH 01-04-2001
DAVID SMITH 01-05-2001
DAVID SMITH 01-06-2001
JOHN SMITH 02-07-2012
JOHN SMITH 02-08-2012
JOHN SMITH 02-09-2012
9 rows selected.
cioè la tua query di base:
select rownum id, name, start_date,
end_date, trunc(end_date)-trunc(start_date) date_range
from table1
definisce semplicemente le date + l'intervallo (ho usato rownum id, ma se hai un PK puoi usarlo invece.
la partizione divide i nostri calcoli per ID (riga univoca):
6 model partition by(id as key)
le misure:
8 measures(name, start_date, cast(null as date) the_date, date_range)
definisce gli attributi che emetteremo/calcoleremo. in questo caso, stiamo lavorando con name e start_date più l'intervallo di righe da generare. inoltre ho definito una colonna the_date
che conterrà la data calcolata (cioè vogliamo calcolare data_inizio + n dove n è compreso tra 0 e l'intervallo.
le regole definiscono COME andremo a popolare le nostre colonne:
9 rules (the_date [for f from 0 to date_range[0] increment 1] = start_date[0] + cv(f),
10 name[any] = name[0]);
così con
the_date [for f from 0 to date_range[0] increment 1]
stiamo dicendo che genereremo il numero di righe che date_range contiene+1 (cioè 6 date in totale). il valore di f
può essere referenziato tramite il cv
(valore corrente).
quindi nella riga 1 per david, avremmo the_date [0] = start_date+0
e successivamente alla riga 2, avremmo the_date [1] = start_date+1
. fino a start_date+5 (cioè il end_date
)
ps per connetterti avresti bisogno di fare qualcosa del genere:
select
A.EMPLOYEE_NAME,
A.START_DATE+(b.r-1) AS INDIVIDUAL_DAY,
TO_CHAR(A.START_DATE,'MM/DD/YYYY') START_DATE,
TO_CHAR(A.END_DATE,'MM/DD/YYYY') END_DATE
FROM table1 A
cross join (select rownum r
from (select max(end_date-start_date) d from table1)
connect by level-1 <= d) b
where A.START_DATE+(b.r-1) <= A.END_DATE
order by 1, 2;
ovvero isolare la connessione tramite una sottoquery, quindi filtrare le righe in cui individual_day> end_date.
ma NON consiglierei questo approccio. le sue prestazioni saranno peggiori rispetto all'approccio del modello (soprattutto se le gamme diventano grandi).