ORACLE 中具有多个父级的父子层次结构

parent-child hierarchy with multiple parents in ORACLE

我试图在 Oracle 11g 中创建父子层次结构树,但遇到这种情况

  1. 每个 CODE 都是唯一的(无重复) 并且在 PARENT_ID
  2. 中有主要父代
  3. 但是当 PARENT_ID IS LIKE '_999' 时有一个例外,那么他们有多个父值在 ETC1 和 ETC2
  4. 之间
  5. 最大等级限制为 4

这是我打算做的树: Flow Tree

下面是用于测试的原始查询

with t as ( 
        select 'A1'    CODE, 'JOB_1_1' CODE_NM, 'A'    PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'A2'    CODE, 'JOB_1_2' CODE_NM, 'A'    PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'A3'    CODE, 'JOB_1_3' CODE_NM, 'A'    PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'B01'   CODE, 'JOB_2_1' CODE_NM, 'A1'   PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'B02'   CODE, 'JOB_2_2' CODE_NM, 'A2'   PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'B03'   CODE, 'JOB_2_3' CODE_NM, 'A3'   PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'C001'  CODE, 'JOB_3_1' CODE_NM, 'B01'  PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'C002'  CODE, 'JOB_3_2' CODE_NM, 'B02'  PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'C003'  CODE, 'JOB_3_3' CODE_NM, 'B03'  PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'D0001' CODE, 'JOB_4_1' CODE_NM, 'C999' PARENT_ID, 'C001' ETC1, 'C003' ETC2 from dual union all 
        select 'D0002' CODE, 'JOB_4_2' CODE_NM, 'C999' PARENT_ID, 'C001' ETC1, 'C003' ETC2 from dual union all 
        select 'D0003' CODE, 'JOB_4_3' CODE_NM, 'C999' PARENT_ID, 'C001' ETC1, 'C003' ETC2 from dual 
    ) 
 select * from t

我已经尝试过的


SELECT LPAD(' ', 4*(LEVEL-1)) ||  CODE AS CODE, CODE_NM, PARENT_ID, LEVEL
FROM    t 
START WITH PARENT_ID = 'A'
CONNECT BY PRIOR  CODE = PARENT_ID 
; 

结果:

-- The result is as you expected, Data with 'C999' PARENT_CODE doesn't show Because not connected anywhere
| CODE       |CODE_NM | PARENT_ID|LEVEL|
| -----------| -------|----------|-----|
|A1          |JOB_1_1 | A        |1    |
|    B01     |JOB_2_1 | A1       |2    |
|        C001|JOB_3_1 | B01      |3    |
|A2          |JOB_1_2 | A        |1    |
|    B02     |JOB_2_2 | A2       |2    |
|        C002|JOB_3_2 | B02      |3    |
|A3          |JOB_1_3 | A        |1    |
|    B03     |JOB_2_3 | A3       |2    |
|        C003|JOB_3_3 | B03      |3    |

我想要的是这样的:

| CODE           |CODE_NM | PARENT_ID|LEVEL|
| -----------    | -------|----------|-----|
|A1              |JOB_1_1 | A        |1    |
|    B01         |JOB_2_1 | A1       |2    |
|        C001    |JOB_3_1 | B01      |3    |
|           D0001|JOB_4_1 |          |4    |
|           D0002|JOB_4_2 |          |4    |
|           D0003|JOB_4_3 |          |4    |
|A2              |JOB_1_2 | A        |1    |
|    B02         |JOB_2_2 | A2       |2    |
|        C002    |JOB_3_2 | B02      |3    |
|           D0001|JOB_4_1 |          |4    |
|           D0002|JOB_4_2 |          |4    |
|           D0003|JOB_4_3 |          |4    |
|A3              |JOB_1_3 | A        |1    |
|    B03         |JOB_2_3 | A3       |2    |
|        C003    |JOB_3_3 | B03      |3    |
|           D0001|JOB_4_1 |          |4    |
|           D0002|JOB_4_2 |          |4    |
|           D0003|JOB_4_3 |          |4    |

我检查的所有来源要么在 table 中有 CODE 重复,要么只是制作一个新的代码来进行不同的分支,关于这个问题的任何输入都将非常有帮助,提前致谢。我的头已经因此受伤了

CONNECT BY 子句添加 OR 条件以检查是否 PRIOR code BETWEEN etc1 and etc2:

with t as ( 
        select 'A1'    CODE, 'JOB_1_1' CODE_NM, 'A'    PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'A2'    CODE, 'JOB_1_2' CODE_NM, 'A'    PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'A3'    CODE, 'JOB_1_3' CODE_NM, 'A'    PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'B01'   CODE, 'JOB_2_1' CODE_NM, 'A1'   PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'B02'   CODE, 'JOB_2_2' CODE_NM, 'A2'   PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'B03'   CODE, 'JOB_2_3' CODE_NM, 'A3'   PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'C001'  CODE, 'JOB_3_1' CODE_NM, 'B01'  PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'C002'  CODE, 'JOB_3_2' CODE_NM, 'B02'  PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'C003'  CODE, 'JOB_3_3' CODE_NM, 'B03'  PARENT_ID, NULL ETC1, NULL ETC2 from dual union all 
        select 'D0001' CODE, 'JOB_4_1' CODE_NM, 'C999' PARENT_ID, 'C001' ETC1, 'C003' ETC2 from dual union all 
        select 'D0002' CODE, 'JOB_4_2' CODE_NM, 'C999' PARENT_ID, 'C001' ETC1, 'C003' ETC2 from dual union all 
        select 'D0003' CODE, 'JOB_4_3' CODE_NM, 'C999' PARENT_ID, 'C001' ETC1, 'C003' ETC2 from dual 
    ) 
SELECT LPAD(' ', 4*(LEVEL-1)) ||  CODE AS CODE, CODE_NM, PARENT_ID, LEVEL
FROM    t 
START WITH PARENT_ID = 'A'
CONNECT BY
        PRIOR CODE = PARENT_ID
OR      PRIOR CODE BETWEEN ETC1 AND ETC2
; 

输出:

CODE CODE_NM PARENT_ID LEVEL
A1 JOB_1_1 A 1
B01 JOB_2_1 A1 2
C001 JOB_3_1 B01 3
D0001 JOB_4_1 C999 4
D0002 JOB_4_2 C999 4
D0003 JOB_4_3 C999 4
A2 JOB_1_2 A 1
B02 JOB_2_2 A2 2
C002 JOB_3_2 B02 3
D0001 JOB_4_1 C999 4
D0002 JOB_4_2 C999 4
D0003 JOB_4_3 C999 4
A3 JOB_1_3 A 1
B03 JOB_2_3 A3 2
C003 JOB_3_3 B03 3
D0001 JOB_4_1 C999 4
D0002 JOB_4_2 C999 4
D0003 JOB_4_3 C999 4

如果您希望 PARENT_ID 列与层次结构的先前级别相匹配,则类似于:

SELECT LPAD(' ', 4*(LEVEL-1)) ||  CODE AS CODE,
       CODE_NM,
       COALESCE(PRIOR code, parent_id) AS PARENT_ID,
       LEVEL
FROM    t 
START WITH PARENT_ID = 'A'
CONNECT BY
        PRIOR CODE = PARENT_ID
OR      PRIOR CODE BETWEEN ETC1 AND ETC2
;

db<>fiddle here