ORACLE 中具有多个父级的父子层次结构
parent-child hierarchy with multiple parents in ORACLE
我试图在 Oracle 11g 中创建父子层次结构树,但遇到这种情况
- 每个 CODE 都是唯一的(无重复) 并且在 PARENT_ID
中有主要父代
- 但是当 PARENT_ID IS LIKE '_999' 时有一个例外,那么他们有多个父值在 ETC1 和 ETC2
之间
- 最大等级限制为 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
我试图在 Oracle 11g 中创建父子层次结构树,但遇到这种情况
- 每个 CODE 都是唯一的(无重复) 并且在 PARENT_ID 中有主要父代
- 但是当 PARENT_ID IS LIKE '_999' 时有一个例外,那么他们有多个父值在 ETC1 和 ETC2 之间
- 最大等级限制为 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