Иерархические запросы

Я создал своего рода таблицу «зависимостей», содержащую все зависимости нашего ночного процесса.

Таблица выглядит так:

GRAND_MODEL | WAITtest2MODEL_NAME
test            test1
test            test2
test            test3
test2           test3
test3           test4
test4           test5

Эта таблица означает -> test нужно дождаться test1, test2, test3, чтобы закончить, но также нужно дождаться test4 и test5, потому что их ждет test3/4. test1 ничего не ждет, test2 ждет test3 и, следовательно, также test4 и, следовательно, test5.

Таким образом, результат должен выглядеть примерно так:

FIRST_MODEL | SECOND_MODEL | THIRD_MODEL | FORTH_MODEL | FIFTH_MODEL | SIXTH_MODEL
 test5           test4            test3       test2          test        NULL 
 test5           test4            test3       test           NULL        NULL
 test4           test3            test2       test           NULL        NULL
.................................

Что я пробовал:

SELECT distinct prior wait_4_model_name as first_m,
                wait_4_model_name as second_m,
                grand_model as third_m
  from (SELECT distinct grand_model, wait_4_model_name
          FROM DEL_SAGI_FOR_HIERARCHY)
connect by NOCYCLE prior grand_model = wait_4_model_name

Но это только создает первый уровень иерархии.

Заранее спасибо.

EDIT: обратите внимание, что могут быть противоположные зависимости, test ждет test1, а test1 ждет test (каждая модель большая, поэтому часть модели может ожидать часть другой модели)


person sagi    schedule 24.07.2016    source источник
comment
Знаете ли вы максимальное количество уровней в иерархии?   -  person MT0    schedule 24.07.2016
comment
Нет, но скажем, 9 достаточно. @MT0   -  person sagi    schedule 24.07.2016
comment
Что касается вашего редактирования: то есть, если есть взаимные зависимости, у вас будут бесконечные последовательности, не так ли? Каков желаемый результат? Разрываете ли вы циклы способом CONNECT BY NOCYCLE?   -  person mathguy    schedule 25.07.2016


Ответы (2)


Настройка Oracle:

CREATE TABLE table_name ( GRAND_MODEL, WAIT_4_MODEL_NAME ) AS
SELECT 'test',  'test1' FROM DUAL UNION ALL
SELECT 'test',  'test2' FROM DUAL UNION ALL
SELECT 'test',  'test3' FROM DUAL UNION ALL
SELECT 'test2', 'test3' FROM DUAL UNION ALL
SELECT 'test3', 'test4' FROM DUAL UNION ALL
SELECT 'test4', 'test5' FROM DUAL;

Запрос:

SELECT REGEXP_SUBSTR( tests, '[^|]+', 1, 1 ) AS first_model,
       REGEXP_SUBSTR( tests, '[^|]+', 1, 2 ) AS second_model,
       REGEXP_SUBSTR( tests, '[^|]+', 1, 3 ) AS third_model,
       REGEXP_SUBSTR( tests, '[^|]+', 1, 4 ) AS fourth_model,
       REGEXP_SUBSTR( tests, '[^|]+', 1, 5 ) AS fifth_model,
       REGEXP_SUBSTR( tests, '[^|]+', 1, 6 ) AS sixth_model,
       REGEXP_SUBSTR( tests, '[^|]+', 1, 7 ) AS seventh_model,
       REGEXP_SUBSTR( tests, '[^|]+', 1, 8 ) AS eighth_model,
       REGEXP_SUBSTR( tests, '[^|]+', 1, 9 ) AS ninth_model
FROM   (
  SELECT SYS_CONNECT_BY_PATH( wait_4_model_name, '|' ) || '|' ||  grand_model AS tests
  FROM  table_name
  CONNECT BY PRIOR grand_model = wait_4_model_name
);

Вывод:

FIRST_MODEL SECOND_MODEL THIRD_MODEL FOURTH_MODEL FIFTH_MODEL SIXTH_MODEL SEVENTH_MODEL EIGHTH_MODEL NINTH_MODEL
----------- ------------ ----------- ------------ ----------- ----------- ------------- ------------ -----------
test1       test                                                                                                 
test2       test                                                                                                 
test3       test                                                                                                 
test3       test2                                                                                                
test3       test2        test                                                                                    
test4       test3                                                                                                
test4       test3        test                                                                                    
test4       test3        test2                                                                                   
test4       test3        test2       test                                                                        
test5       test4                                                                                                
test5       test4        test3                                                                                   
test5       test4        test3       test                                                                        
test5       test4        test3       test2                                                                       
test5       test4        test3       test2        test                                                           
person MT0    schedule 24.07.2016
comment
После нескольких корректировок все заработало как часы. Спасибо. - person sagi; 24.07.2016
comment
К сожалению, это решение объединяет строки, чтобы затем снова разделить их, также требуя, чтобы разделитель не встречался в самих данных. - person trincot; 24.07.2016
comment
Пожалуйста, посмотрите на мой следующий вопрос к этому здесь - stackoverflow.com/questions/38551931/ выбор лучшего вывода :) - person sagi; 24.07.2016

Вот решение, которое не требует объединения строк и повторного разделения:

select    a.wait_4_model_name model1,
          a.grand_model       model2,
          b.grand_model       model3,
          c.grand_model       model4,
          d.grand_model       model5,
          e.grand_model       model6
from      DEL_SAGI_FOR_HIERARCHY a
left join DEL_SAGI_FOR_HIERARCHY b ON a.grand_model = b.wait_4_model_name
left join DEL_SAGI_FOR_HIERARCHY c ON b.grand_model = c.wait_4_model_name
left join DEL_SAGI_FOR_HIERARCHY d ON c.grand_model = d.wait_4_model_name
left join DEL_SAGI_FOR_HIERARCHY e ON d.grand_model = e.wait_4_model_name
where     a.wait_4_model_name not in (
              select grand_model from DEL_SAGI_FOR_HIERARCHY)
order by  1, 2, 3, 4, 5, 6

Выходные данные для образца данных:

+--------+--------+--------+--------+--------+--------+
| MODEL1 | MODEL2 | MODEL3 | MODEL4 | MODEL5 | MODEL6 |
+--------+--------+--------+--------+--------+--------+
| test1  | test   |    -   |   -    |   -    |   -    |
| test5  | test4  | test3  | test   |   -    |   -    |
| test5  | test4  | test3  | test2  | test   |   -    |
+--------+--------+--------+--------+--------+--------+

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

person trincot    schedule 24.07.2016
comment
Спасибо за решение, я предпочитаю иерархические запросы, но +1 за идею. Буду признателен, если вы посмотрите на этот вопрос: stackoverflow.com/questions/38551931 /выбор лучшего результата - person sagi; 24.07.2016
comment
Производительность этого не будет велика, так как вам нужно одно сканирование таблицы для каждого уровня иерархии. - person MT0; 24.07.2016
comment
Только если вы не ставите индексы на эти поля. При правильном наборе индексов это не сканирование таблицы. На самом деле, с правильно настроенным индексом движку даже не нужно обращаться к самой таблице, он может сделать все это с помощью индекса. - person trincot; 24.07.2016