Иерархический запрос Oracle с несколькими корнями возвращает дочерние элементы как корни - PullRequest
0 голосов
/ 29 ноября 2018

У меня есть следующие данные в таблице:

ID  PID
B   A
C   B
D   B
E   D
G   F    
H   G
I   H

Вот сценарий создания / вставки для вашего удобства:

drop table hierarchic_test;

create table hierarchic_test(
     id varchar2(1),
     pid varchar2(1)
);

insert into hierarchic_test(id, pid) values('B', 'A');
insert into hierarchic_test(id, pid) values('C', 'B');
insert into hierarchic_test(id, pid) values('D', 'B');
insert into hierarchic_test(id, pid) values('E', 'D');
insert into hierarchic_test(id, pid) values('G', 'F');
insert into hierarchic_test(id, pid) values('H', 'G');
insert into hierarchic_test(id, pid) values('I', 'H');

Я пытаюсь получить иерархический запрос, работающий над этимданные.Мои реальные данные будут содержать несколько корней с несколькими листьями.Поэтому начинать с этого нельзя.

Это то, что я до сих пор извлек из документации, которую я нашел в Интернете:

select level, hierarchic_test.* from hierarchic_test
connect by prior hierarchic_test.id      = hierarchic_test.pid
order siblings by hierarchic_test.id

Результаты, которые я получаю:

LEVEL ID   PID
1     B    A
2     C    B
2     D    B
3     E    D
1     C    B
1     D    B
2     E    D
1     E    D
1     G    F
2     H    G
3     I    H
1     H    G
2     I    H
1     I    H

Результаты, которые я ожидаю, должны выглядеть следующим образом:

LEVEL ID    PID
1     B     A
2     C     B
2     D     B
3     E     D
1     G     F
2     H     G
3     I     H  

Это также, похоже, документально подтвержденное поведение при здесь .Если я использую start с:

select level, hierarchic_test.* from hierarchic_test
start with hierarchic_test.id = 'A'
connect by prior hierarchic_test.id      = hierarchic_test.pid
order siblings by hierarchic_test.id

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

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Ваш запрос:

select level,
       hierarchic_test.*
from   hierarchic_test
connect by prior hierarchic_test.id      = hierarchic_test.pid
order siblings by hierarchic_test.id

Извлекает то, что вы считаете множественными дубликатами, потому что вы не сказали, что нужно START WITH, поэтому оно будет начинаться со всего:

LEVEL ID     PID
----- ------ ------
1     B      A
1     C      A
└ 2   └ D    └ C
1     D      C
1     A      (null)
├ 2   ├ B    ├ A
└ 2   └ C    └ A
  └ 3   └ D    └ C

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

Если вы толькохотите START WITH строки, которые не имеют соответствующей родительской строки:

SQL Fiddle

Настройка схемы Oracle 11g R2 :

create table hierarchic_test( id,  pid ) AS
  SELECT 'A', NULL FROM DUAL UNION ALL
  SELECT 'B', 'A' FROM DUAL UNION ALL
  SELECT 'C', 'A' FROM DUAL UNION ALL
  SELECT 'D', 'C' FROM DUAL UNION ALL
  SELECT 'F', 'E' FROM DUAL UNION ALL
  SELECT 'G', 'F' FROM DUAL;

Запрос 1 :

SELECT level,
       h.*
FROM   hierarchic_test h
START WITH pid IS NULL
OR         pid NOT IN ( SELECT id FROM hierarchic_test )
CONNECT BY PRIOR id = pid
ORDER SIBLINGS BY id

Результаты :

| LEVEL | ID |    PID |
|-------|----|--------|
|     1 |  A | (null) |
|     2 |  B |      A |
|     2 |  C |      A |
|     3 |  D |      C |
|     1 |  F |      E |
|     2 |  G |      F |
0 голосов
/ 29 ноября 2018

Вы должны иметь возможность использовать несколько узлов для начала, если вы создадите какой-либо запрос, который возвращает несколько значений, и поместите его в IN (...):

select level, hierarchic_test.* from hierarchic_test
start with hierarchic_test.id IN (
  SELECT 'A' AS start_candidate FROM DUAL UNION ALL 
  SELECT 'WHATEVER' FROM DUAL UNION ALL 
  ...
)
connect by prior hierarchic_test.id = hierarchic_test.pid
order siblings by hierarchic_test.id

или если PID равен нулю, всегданачальный узел:

select level, hierarchic_test.* from hierarchic_test
start with hierarchic_test.pid IS NULL
connect by prior hierarchic_test.id = hierarchic_test.pid
order siblings by hierarchic_test.id

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...