2

in Oracle 10g Angenommen, ich habe eine Tabelle wie folgt aus:Split Zeile in mehrere Zeilen basierend auf der Zeit

id | start_date | end_date | value | parent_id 
---------------------------------------------------- 
1  | 01-01-2001 | 01-01-2002 | aaaaaa | 3 
2  | 01-01-2003 | 01-01-2004 | bbbbbb | 3 
3  | 01-01-2000 | 01-01-2005 | cccccc | 4 
4  | 01-01-1999 | 01-01-2006 | dddddd |null 

Ich möchte Lücken sehen, in die vom übergeordneten überlappungsfrei gefüllt werden. Genauer gesagt soll das Ergebnis so etwas wie:

start_date | end_date | value | depth 
----------------------------------------- 
01-01-1999 | 01-01-2000 | dddddd | 2 
01-01-2000 | 01-01-2001 | cccccc | 1 
01-01-2001 | 01-01-2002 | aaaaaa | 0 
01-01-2002 | 01-01-2003 | cccccc | 1 
01-01-2003 | 01-01-2004 | bbbbbb | 0 
01-01-2004 | 01-01-2005 | cccccc | 1 
01-01-2005 | 01-01-2006 | dddddd | 2 

Die Tiefe die Zahl der Eltern ist auf den Wert zu erhalten, aber kann dann 2, mehr sein, so wäre es am besten Rekursion zu verwenden.

Sie können davon ausgehen, dass es keine Überlappung für die Zeiträume gibt, die dasselbe übergeordnete Element haben. All dies ohne Verwendung gespeicherter Prozeduren, aber Sie können CTEs, Fensterfunktionen usw. mitbringen.

+0

Eines der wichtigsten Probleme mit Ihrem Voraussetzung ist Ihre Definition von "Tiefe". Um die Tiefe einer bestimmten Zeile zu berechnen, müssen Sie alle untergeordneten Elemente navigieren, um zu sehen, wie viele Ebenen vorhanden sind. Sehr teuer. Es wäre viel besser, wenn Sie es umgekehrt hätten. Das heißt, dass "dddddd" die Tiefe "0" ist, "cccccc" die Tiefe "1" ist und "aaaaaa" und "bbbbbb" die Tiefe "2" sind. – sstan

+0

@sstan, die Definition der Tiefe kann umgekehrt sein, wenn Sie möchten. Mit anderen Worten, fühlen Sie sich frei, von den Eltern anstatt von den Kindern zu beginnen. – ortwin45

Antwort

1

Ja, das ist möglich. Ich weiß nicht, wie gut es funktionieren wird.

Die Abfrage wird in 3 Haupt CTEs unterteilt:

  1. A CTE die gewünschten Datumsbereiche zu Ausgabezwecken
  2. A CTE die maximale Tiefe in dem Baum
  3. A CTE berechnen zu erzeugen beizutreten alle Daten zusammen und kennzeichnen die "wünschenswerteren" Zeilen nach Tiefe unter Verwendung der row_number() Fensterfunktion.

Abfrage:

with date_ranges_cte as (
    select add_months(date '1999-01-01', (rownum-1) * 12) as start_date, 
     add_months(date '1999-01-01', rownum * 12) as end_date 
    from dual 
    connect by rownum <= 7 
), max_level_cte as (
    select max(level) as max_level 
    from tbl 
    start with parent_id is null 
connect by prior id = parent_id 
), main_cte as (
    select d.start_date, 
     d.end_date, 
     t.value, 
     t.lvl, 
     row_number() over (partition by d.start_date, d.end_date order by t.lvl desc, t.id) as rn 
    from date_ranges_cte d 
    join (select t.*, level as lvl 
      from tbl t 
      start with parent_id is null 
     connect by prior id = parent_id) t 
     on ((d.start_date >= t.start_date and d.start_date < t.end_date) 
      or (d.end_date > t.start_date and d.end_date <= t.end_date)) 
) 
select m.start_date, 
     m.end_date, 
     m.value, 
     l.max_level - m.lvl as depth 
    from main_cte m 
    cross join max_level_cte l 
where m.rn = 1 
order by m.start_date 

Wenn Sie ok sind die Definition von depth Umkehr, dann können wir von einem der CTEs loszuwerden:

with date_ranges_cte as (
    select add_months(date '1999-01-01', (rownum-1) * 12) as start_date, 
     add_months(date '1999-01-01', rownum * 12) as end_date 
    from dual 
    connect by rownum <= 7 
), main_cte as (
    select d.start_date, 
     d.end_date, 
     t.value, 
     t.lvl, 
     row_number() over (partition by d.start_date, d.end_date order by t.lvl desc, t.id) as rn 
    from date_ranges_cte d 
    join (select t.*, level as lvl 
      from tbl t 
      start with parent_id is null 
     connect by prior id = parent_id) t 
     on ((d.start_date >= t.start_date and d.start_date < t.end_date) 
      or (d.end_date > t.start_date and d.end_date <= t.end_date)) 
) 
select start_date, 
     end_date, 
     value, 
     lvl - 1 as depth 
    from main_cte 
where rn = 1 
order by start_date 
+0

Ich tippe meinen Hut zu Ihnen, Herr. Ich werde etwas Zeit brauchen, um zu lernen, was Sie mir gezeigt haben, aber ein erster Test zeigt, dass dies genau das tut, was ich brauche. – ortwin45

+0

Kein Problem. Wenn Sie die Abfrage in ihre kleineren Komponenten zerlegen und sie einzeln ausführen, werden Sie sicher herausfinden können, wie sie funktioniert. – sstan

Verwandte Themen