2

Предположим, что в Oracle 10g, у меня есть таблица вроде этого:Split строки на несколько строк в зависимости от времени

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 

Я хотел бы видеть какие-либо пробелы в заполняться родителя без перекрытия. Более конкретно результат должен быть что-то вроде:

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 

Глубина является число родителей, чтобы добраться до значения, но может быть более 2, так что было бы лучше использовать рекурсию.

Можно предположить, что для периодов, имеющих один и тот же родительский элемент, нет совпадений. Все это без использования хранимых процедур, но не стесняйтесь приносить CTE, оконные функции и т. Д.

+0

Одна из главных проблем, с вашим Требование - это ваше определение «глубина». Чтобы рассчитать «глубину» одной определенной строки, вам придется перемещать всех детей, чтобы увидеть, сколько уровней существует. Очень дорого. Было бы намного лучше, если бы у вас было наоборот. То есть, 'dddddd' является глубиной' 0', 'cccccc' является глубиной' 1', а 'aaaaaa' и' bbbbbb' являются глубиной '2'. – sstan

+0

@sstan, определение глубины может быть наоборот, если хотите. Другими словами, не стесняйтесь начинать с родителей, а не с детей. – ortwin45

ответ

1

Да, это возможно. Не знаю, насколько хорошо он будет работать.

Запрос разделен на 3 основных КТР:

  1. КТР, чтобы генерировать желаемые диапазоны дат для выходных целей
  2. КТР рассчитать глубину макс в дереве
  3. КТР, чтобы присоединиться все данные вместе и обозначают более «желательные» строки по глубине с помощью оконной функции row_number().

Запрос:

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 

Если вы нормально реверсирования определение depth, то мы можем избавиться от одного из КТР:

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

Я подсказываю тебе свою шляпу, сэр. Мне нужно некоторое время, чтобы узнать, что вы показали мне, но первый тест показывает, что это делает именно то, что мне нужно. – ortwin45

+0

Нет проблем. Если вы разбиваете запрос на свои меньшие компоненты и запускаете их индивидуально, я уверен, что вы сможете выяснить, как это работает. – sstan

 Смежные вопросы

  • Нет связанных вопросов^_^