Oracle
 sql >> Datenbank >  >> RDS >> Oracle

So generieren Sie Zeilen für den Datumsbereich nach Schlüssel

bei 10g/11g kannst du dafür die Musterklausel verwenden.

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.

dh Ihre Basisabfrage:

select rownum id, name, start_date,
       end_date, trunc(end_date)-trunc(start_date) date_range
  from table1

definiert nur die Daten + den Bereich (ich habe die Rownum-ID verwendet, aber wenn Sie eine PK haben, können Sie diese stattdessen verwenden.

Die Partition teilt unsere Berechnungen nach ID (eindeutige Zeile):

6  model partition by(id as key)

die Maßnahmen:

8        measures(name, start_date, cast(null as date) the_date, date_range)

definiert die Attribute, die wir ausgeben/berechnen. In diesem Fall arbeiten wir mit dem Namen und dem Startdatum plus dem Bereich der zu generierenden Zeilen. zusätzlich habe ich eine Spalte the_date definiert das das berechnete Datum enthält (d.h. wir wollen start_date + n berechnen, wobei n von 0 bis zum Bereich reicht.

Die Regeln definieren, WIE wir unsere Spalten füllen werden:

9        rules (the_date [for f from 0 to date_range[0] increment 1]  = start_date[0] + cv(f),
10               name[any] = name[0]);

also mit 

the_date [for f from 0 to date_range[0] increment 1]

wir sagen, dass wir die Anzahl der Zeilen generieren werden, die date_range +1 enthält (dh insgesamt 6 Daten). der Wert von f kann über den cv referenziert werden (aktueller Wert) Funktion.

In Zeile 1 für David hätten wir also the_date [0] = start_date+0 und anschließend in Zeile 2 hätten wir the_date [1] = start_date+1 . bis hin zum start_date+5 (d.h. das end_date )

p.s.für connect by müssten Sie so etwas tun:

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;

d. h. isolieren Sie die Verbindung von zu einer Unterabfrage und filtern Sie dann die Zeilen heraus, in denen individual_day> end_date.

aber ich würde diesen Ansatz NICHT empfehlen. seine Leistung wird im Vergleich zum Modellansatz schlechter sein (insbesondere wenn die Reichweiten groß werden).