Нужен SQL-запрос для иерархических данных в плоском результирующем наборе

#sql #oracle #pivot #recursive-query

#sql #Oracle #сводный #рекурсивный запрос

Вопрос:

Есть таблица: PS_POSITION_TBL

 position_nbr      reports_to              descr        
 038              143                     DIRECTOR 
 0418             143                     ADVISOR                        
 114              143                     DG                              
 346              114                     Manager                        
 202              114                     Lead 
  

Идея, которую мы хотим построить иерархию выше

случай 1: 038, 0418 и 114 сообщает о 143

случай 2: 346 и 202 отчетов для 114

итак, самый высокий уровень — level1, который равен 143, затем 038,0418,114 — уровень 2, поскольку они отчитываются перед уровнем 1, затем 346 и 202 — уровень 3, и они попадают под сегмент уровня 3, и они отчитываются перед уровнем 2

Они могут достигать уровня 8 (МАКСИМУМ)

Что мне нужно, так это запрос для получения данных в приведенном ниже формате в Oracle:

 level1  level2   level3  level4 level5 level6 level7 level8      descr
 143                                                             CEO            
           038                                                   DIRECTOR        
           0418                                                  ADVISOR         
           114                                                   DG              
                    346                                          Manager         
                    202                                          Lead    
  

Комментарии:

1. Позиции 143 нет в вашей таблице. Откуда вы знаете, что такое descr ?

Ответ №1:

 select    level1,level2,level3,level4,level5,level6,level7,level8,descr

from     (select        level as n,position_nbr as id,descr,position_nbr

          from          (         select position_nbr ,reports_to ,descr from PS_POSITION_TBL 
                        union all select 143          ,null       ,'CEO' from dual
                        )  t

          start with    reports_to is null

          connect by    reports_to = prior position_nbr
          ) 
          pivot (max(position_nbr) for n in (1 as level1,2 as level2,3 as level3,4 as level4,5 as level5,6 as level6,7 as level7,8 as level8))
;
  

или

 select    decode (n,1,position_nbr) as level1
         ,decode (n,2,position_nbr) as level2
         ,decode (n,3,position_nbr) as level3
         ,decode (n,4,position_nbr) as level4
         ,decode (n,5,position_nbr) as level5
         ,decode (n,6,position_nbr) as level6
         ,decode (n,7,position_nbr) as level7
         ,decode (n,8,position_nbr) as level8
         ,descr

from     (select          level as n,position_nbr,descr

          from          (         select position_nbr ,reports_to ,descr from PS_POSITION_TBL 
                      union all select 143          ,null       ,'CEO' from dual
                      )  t

          start with    reports_to is null

          connect by    reports_to = prior position_nbr
          ) 
;
  

Комментарии:

1. Это правильная идея, но она жестко кодирует 143 вместо того, чтобы находить его по данным. 143 можно найти, например, выбрав distinct из reports_to, которые не находятся в position_nbr.

2. @mathguy, ты просто догадываешься, как и я. Вы не знаете, что 143 не находится в position_nbr (и вы не получите описание, подобное этому)

3. Если 143 находится в position_nbr, то это не уровень 1, не так ли? В этом весь смысл! И описание следует оставить нулевым; то, что OP показывает на выходе, нигде не содержится во входных данных или в требовании проблемы. (Это можно было бы поместить в последнее, например, «для идентификаторов уровня 1, у которых нет описания, введите жесткий код «CEO» для описания».)

4. @mathguy, совсем нет. 143 может находиться в position_nbr и на уровне 1, если reports_to, например, равен НУЛЮ. Поскольку эта проблема неясна, я представил решение, которое решает вопрос в соответствии с заданными данными.

5. @jujadhav, это отвечает на твой вопрос?

Ответ №2:

Следующий запрос предоставит вам иерархический набор, дополненный слева символом LEVEL :

 SELECT LPAD(' ', level * 2, ' ') || TO_CHAR(position_nbr), descr
  FROM PS_POSITION_TBL
CONNECT BY PRIOR position_nbr = reports_to
START WITH reports_to IS NULL;
  

Если вас не устраивает отображение уровня в одном столбце ( LEVEL ) и вам нужен столбец для каждого уровня, вы можете использовать PIVOT на основе LEVEL , но это затруднит упорядочивание.