в 10g/11g можете да използвате моделната клауза за това.
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.
т.е. вашата основна заявка:
select rownum id, name, start_date,
end_date, trunc(end_date)-trunc(start_date) date_range
from table1
просто дефинира датите + диапазона (използвах rownum id, но ако имате PK, можете да използвате това вместо това.
дялът разделя нашите изчисления по ID (уникален ред):
6 model partition by(id as key)
мерките:
8 measures(name, start_date, cast(null as date) the_date, date_range)
дефинира атрибутите, които ще извеждаме/изчисляваме. в този случай работим с име и начална_дата плюс диапазона от редове за генериране. освен това дефинирах колона the_date
която ще съдържа изчислената дата (т.е. искаме да изчислим начална_дата + n, където n е от 0 до диапазона.
правилата определят КАК ще попълним нашите колони:
9 rules (the_date [for f from 0 to date_range[0] increment 1] = start_date[0] + cv(f),
10 name[any] = name[0]);
така и с
the_date [for f from 0 to date_range[0] increment 1]
ние казваме, че ще генерираме броя редове, които date_range съдържа+1 (т.е. общо 6 дати). стойността на f
може да се посочи чрез cv
(текуща стойност) функция.
така че на ред 1 за Дейвид ще имаме the_date [0] = start_date+0
и впоследствие на ред 2 ще имаме the_date [1] = start_date+1
. целия път до начална_дата+5 (т.е. end_date
)
p.s. за свързване от трябва да направите нещо подобно:
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;
т.е. изолирайте свързването чрез към подзаявка, след което филтрирайте редовете, където individual_day> end_date.
но НЕ БИХ препоръчал този подход. неговата производителност ще бъде по-лоша в сравнение с моделния подход (особено ако диапазоните станат големи).