Цикл в оракуле sql - PullRequest
       3

Цикл в оракуле sql

0 голосов
/ 19 декабря 2018

Я хочу добавить столбец ID_last в таблицу слева внизу.Таблица примеров состоит из двух последовательностей по 6 и 8 строк.Мне нужно иметь дело со многими последовательностями и неизвестным / бесконечным числом строк на последовательность / циклов на последовательность.Последовательность начинается, когда ID отсутствует в ID_new, и последовательность останавливается, когда ID_new отсутствует в ID.Я хочу знать последний ID_new всех идентификаторов в последовательности (как в таблице справа).

Как мне сделать это с помощью SQL (оракул)?

Помощь очень ценится!

See image of table :)

Ответы [ 3 ]

0 голосов
/ 19 декабря 2018

Если у вас Oracle 11gR2 или более поздней версии, вы можете использовать рекурсивный запрос, подобный этому (при условии, что ваша таблица называется tbl):

with tbl2(id, id_new, id_last, lvl) as (
    select     id, id_new, id_new, 1 
    from       tbl
    union all
    select     tbl2.id, tbl2.id_new, tbl.id_new, tbl2.lvl+1 
    from       tbl2
    inner join tbl 
            on tbl.id = tbl2.id_last
)
select unique id, id_new, 
       first_value(id_last) over (partition by id, id_new order by lvl desc) id_last 
from   tbl2

Это не относится к циклам (я не делалполучить ответ на мой комментарий об этом).

0 голосов
/ 19 декабря 2018

Поскольку с помощью этого запроса можно определить последние идентификаторы в любой последовательности:

select id_new from YourData yd
 where not exists (select 1 from YourData yd2
                    where yd2.id = yd.id_new);

Мы можем рассматривать проблему как иерархический запрос с корнями в идентифицированных значениях ID_Last, возвращая корневой идентификатор как ID_Last:

select id
     , id_new
     , CONNECT_BY_ROOT id_new ID_Last
  from YourData yd
  connect by NOCYCLE id_new = prior id
 start with not exists (select 1 from YourData yd2
                         where yd2.id = yd.id_new)

Альтернативно это можно записать как рекурсивный запрос, используя первый запрос выше (с дополнительными столбцами) в качестве запроса привязки.Чтобы избежать циклов, нам нужно добавить столбец для отслеживания уже посещенных узлов и проверить его в рекурсивной части запроса:

With Recur(id, id_new, id_last, nodes) as (
  select id
       , id_new
       , id_new
       , ':'||id||':'
    from YourData yd1
   where not exists (select 1 from YourData yd2
                      where yd2.id = yd1.id_new)
   union all
  select yd.id
       , yd.id_new
       , r.id_last
       , r.nodes||yd.id||':'
    from YourData yd
    join Recur r
      on r.id = yd.id_new
     and r.nodes not like '%:'||yd.id||':%' -- Avoid cycles
)
select id, id_new, id_last
  from Recur
 order by id_last
     , nodes desc;
0 голосов
/ 19 декабря 2018

Вы не указали имя таблицы, поэтому я предполагаю, что она называется table1 .

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

-- sample data
with table1 as (select 11 as id, 12 as id_new from dual
    union all select 12, 5 from dual
    union all select 5, 18 from dual
    union all select 18, 17 from dual
    union all select 17, 28 from dual
    union all select 28, 13 from dual
    union all select 25, 31 from dual
    union all select 31, 22 from dual
    union all select 22, 41 from dual
    union all select 41, 33 from dual
    union all select 33, 39 from dual
    union all select 39, 30 from dual
    union all select 30, 45 from dual
    union all select 45, 24 from dual)
-- query
select regexp_substr(id_path, '[^>]+', 1, 1) as root, 
  id_new as id_last
from (select CONNECT_BY_ISLEAF isleaf, sys_connect_by_path(id, '>') as id_path, id_new
      from table1
      connect by prior id_new = id)
where isleaf = 1
;

Я думаю, что это должно работать как заявление об обновлении, но я не проверял его.

merge into table1 t
  using (select regexp_substr(id_path, '[^>]+', 1, 1) root, id_new as id_last
        from (select CONNECT_BY_ISLEAF isleaf, sys_connect_by_path(r.id, '>') as id_path, r.id_new
              from table1 r
              connect by prior r.id_new = r.id)
        where isleaf = 1) u
  on (t.id = u.root)
when matched then update
  set t.id_last = u.id_last;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...