具有多个根的Oracle分层查询将子级作为根返回

时间:2018-11-29 09:06:40

标签: sql oracle oracle11g

我在表中有以下数据:

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  

这似乎也是here上的文档行为。如果我使用以下开头:

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 with。你能指出我的错误/指出正确的方向吗?

2 个答案:

答案 0 :(得分:0)

如果您编写一些返回多个值的查询并将其放在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为null总是一个起始节点:

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

第一种形式使您可以准确选择要开始的节点,后一种形式依赖于节点的某些公共属性

答案 1 :(得分:0)

您的查询:

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

Results

| LEVEL | ID |    PID |
|-------|----|--------|
|     1 |  A | (null) |
|     2 |  B |      A |
|     2 |  C |      A |
|     3 |  D |      C |
|     1 |  F |      E |
|     2 |  G |      F |