2013-05-02 3 views
1

У меня есть входные данные, которые состоят из ID, prev, current и next node (не отсортированы).
Мне нужно найти путь между первой и последней страницей для каждого идентификатора, который охватывает все пройденные узлы.
например, если мои входные данные подобны:
первый столбец ID, второй столбец - prev_node, третий столбец - текущий узел, четвертый столбец - следующий узел.
Prev_node будет пустым для начального значения и следующий узел будет пустым для последнего значенияПолный путь между двумя узлами циклической структуры pl/sql

вход

id prev current next  
------------------------ 
1 a  b  c 
1 a  e  f 
1 a  b  g 
1 a  b  o  
1 b  c  d 
1 b  g  h 
1 b  o  p 
1 c  d  a 
1 c  b  g 
1 d  a  e 
1 e  f  e 
1 e  f  f 
1 f  e  f 
1 f  f  f 
1 f  f  a 
1 f  a  b 
1 g  h  i 
1 h  i  j 
1 h  j  i 
1 i  j  i 
1 i  i  k 
1 i  k  l 
1 j  i  i 
1 k  l  m 
1 l  m  n 
1 l  n  a 
1 m  n  a 
1 n  a  b 
1 o  p  q 
1 p  q  r 
1 q  r  s 
1 r  s  t 
1 s  t  u 
1 t  u  v 
1 u  v  w 
1 v  w  x 
1 w  x   
1   a  b 

выход должен быть путь текущего узла, как -

ID current 
------------- 
1  a 
1  b 
1  c 
1  d 
1  a 
1  e 
1  f 
1  e 
1  f 
1  f 
1  f 
1  a 
1  b 
1  b 
1  g 
1  h 
1  i 
1  j 
1  j 
1  i 
1  i 
1  k 
1  l 
1  m 
1  n 
1  n 
1  a 
1  b 
1  o 
1  p 
1  q 
1  r 
1  s 
1  t 
1  u 
1  v 
1  w 
1  x 

Здесь будет много идентификаторов с похожими данными. Я показал только один ID (1). Также здесь я использовал алфавиты, которые на самом деле будут длиной 200-500 символов. Я пробовал SQL-подход с небольшой модификацией, он отлично работает, если идентификатор имеет 100 или меньше строк, но дает ошибку конкатенации строк для большего количества строк (даже после преобразования длинной строки в число). Кто-нибудь может предложить надежный подход, основанный на процедурах. Я пробовал некоторые, но он не работает для более чем 300 строк для ID.

ответ

0
with 
    t_n as (
    select prev, curr, next, rownum n from your_table 
), 
    t_br as (
    select prev, curr, 
     '<'||listagg(n, '|<')within group(order by n)||'|' br, 
     count(0) cnt 
    from t_n 
    group by prev, curr 
), 
    t_mp as (
    select 
     '|'||listagg(list)within group(order by null) list 
    from (
     select replace(br, '<') list 
     from t_br 
     where cnt > 1 
    ) 
), 
    t_path(step, curr, next, used) as (
    select 1, curr, next, '' 
    from t_n where prev is null 
    union all 
    select step + 1, t_br.curr, t_n.next, 
     case when instr(list, '|'||n||'|') = 0 then used 
     else used||n||'|' end 
    from t_mp, t_path 
    join t_br 
     on next = t_br.curr and t_path.curr = prev 
    join t_n 
     on n = regexp_substr(br,'^(<('||used||'0)\|)*(<(\d+))?',1,1,'',4) 
) cycle step set is_cycle to 'Y' default 'N' 
select step, curr from t_path order by 1; 

fiddle

+0

спасибо за Ваш ответ. Но я думаю, что один цикл пропущен с использованием этого кода. например: есть 3 a, b на входе, но на выходе am получается только два a, b. Не могли бы вы помочь мне в вопросе, почему это может произойти? – user2342436

+0

@ user2342436 - Есть 3 a, b на выходе (шаги 1, 12, 24) –

+0

большое спасибо Егору. Большая помощь!! Будет проверять запрос со всеми условиями. – user2342436

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