不使用子查询和函数展平层次结构查询 PLSQL
Flatten a hierarchy query PLSQL not using subqueries and functions
我是 PLSQL 的新手,开始学习如何高效地编写查询。我面临着使用 Connect By 扁平化员工报告层次结构的挑战。
目前,我们在员工报告中有五个级别的层次结构,但我们的查询不应限制为 5 个级别。将来,如果我们有新的报告级别,相同的查询应该可以在不做任何更改的情况下工作。
结果集中的所有记录都应该在同一级别结束,如果经理没有向 him/her 报告的员工,那么级别 5 应该是经理本身。您可以看到下面的预期结果以便更好地理解。示例:经理 1 和经理 3
注意:为了获得更好的性能,我不想为此请求使用任何函数或子查询。
预期结果:
Level 1 Level 2 Level 3 Level 4 Level 5 **(Level 6, Level 7 ) for future**
---------- ---------- ------- ------- ------ ------ -------
President VP1 Dir1 Mgr1 Mgr1
President VP1 Dir2 Mgr2 Emp1
President VP2 Dir3 Mgr4 Emp2
President VP2 Dir4 Mgr3 Mgr3
President VP3 Dir5 Mgr5 Emp3
President VP3 Dir6 Mgr6 Emp4
President VP4 Dir7 Mgr7 Emp5
对我来说,以下看起来像你想要的:
with normalized$(super_id, emp_id) as (
select null, 'president' from dual
union all
select 'president', 'vp1' from dual
union all
select 'president', 'vp2' from dual
union all
select 'president', 'vp3' from dual
union all
select 'president', 'vp4' from dual
union all
select 'vp1', 'dir1' from dual
union all
select 'vp1', 'dir2' from dual
union all
select 'vp2', 'dir3' from dual
union all
select 'vp2', 'dir4' from dual
union all
select 'vp3', 'dir5' from dual
union all
select 'vp3', 'dir6' from dual
union all
select 'vp4', 'dir7' from dual
union all
select 'dir1', 'mgr1' from dual
union all
select 'dir2', 'mgr2' from dual
union all
select 'dir3', 'mgr4' from dual
union all
select 'dir4', 'mgr3' from dual
union all
select 'dir5', 'mgr5' from dual
union all
select 'dir6', 'mgr6' from dual
union all
select 'dir7', 'mgr7' from dual
union all
select 'mgr2', 'emp1' from dual
union all
select 'mgr4', 'emp2' from dual
union all
select 'mgr5', 'emp3' from dual
union all
select 'mgr6', 'emp4' from dual
union all
select 'mgr7', 'emp5' from dual
union all
-- note: these two are added here for testing the levels 6 and 7
select 'emp2', 'sub1' from dual
union all
select 'sub1', 'subsub1' from dual
),
denormalized$ as (
select ora_hash(emp_id) as hierarchy_id, -- note: this is just "some" row id; use whatever else you wish
sys_connect_by_path(emp_id, '|') as hierarchy
from normalized$ N
where connect_by_isleaf = 1
start with super_id is null
connect by prior emp_id = super_id
),
split$ as (
select hierarchy_id,
regexp_substr(hierarchy, '\|([^|]*)', 1, 1, null, 1) as h_lvl_1,
regexp_substr(hierarchy, '\|([^|]*)', 1, 2, null, 1) as h_lvl_2,
regexp_substr(hierarchy, '\|([^|]*)', 1, 3, null, 1) as h_lvl_3,
regexp_substr(hierarchy, '\|([^|]*)', 1, 4, null, 1) as h_lvl_4,
regexp_substr(hierarchy, '\|([^|]*)', 1, 5, null, 1) as h_lvl_5,
regexp_substr(hierarchy, '\|([^|]*)', 1, 6, null, 1) as h_lvl_6,
regexp_substr(hierarchy, '\|([^|]*)', 1, 7, null, 1) as h_lvl_7
from denormalized$
),
filled$ as (
select hierarchy_id,
h_lvl_1,
coalesce(h_lvl_2, h_lvl_1) as h_lvl_2,
coalesce(h_lvl_3, h_lvl_2, h_lvl_1) as h_lvl_3,
coalesce(h_lvl_4, h_lvl_3, h_lvl_2, h_lvl_1) as h_lvl_4,
coalesce(h_lvl_5, h_lvl_4, h_lvl_3, h_lvl_2, h_lvl_1) as h_lvl_5,
coalesce(h_lvl_6, h_lvl_5, h_lvl_4, h_lvl_3, h_lvl_2, h_lvl_1) as h_lvl_6,
coalesce(h_lvl_7, h_lvl_6, h_lvl_5, h_lvl_4, h_lvl_3, h_lvl_2, h_lvl_1) as h_lvl_7
from split$
)
select *
from filled$
;
...屈服...
HIERARCHY_ID H_LVL_1 H_LVL_2 H_LVL_3 H_LVL_4 H_LVL_5 H_LVL_6 H_LVL_7
------------ --------- ------- ------- ------- ------- ------- -------
490409852 president vp1 dir1 mgr1 mgr1 mgr1 mgr1
1220769441 president vp1 dir2 mgr2 emp1 emp1 emp1
849214331 president vp2 dir3 mgr4 emp2 sub1 subsub1
530886880 president vp2 dir4 mgr3 mgr3 mgr3 mgr3
1157603336 president vp3 dir5 mgr5 emp3 emp3 emp3
1467614544 president vp3 dir6 mgr6 emp4 emp4 emp4
523144703 president vp4 dir7 mgr7 emp5 emp5 emp5
但是,没有办法(我知道)你可以(没有 table 函数 returning sys.anyDataSet
)可能对 return 任意列数的查询,所以让我们只坚持层次结构中假定的最大级别数,如果上面的查询是 7.
注意 可以通过不同的方式完成按路径连接及其后续拆分 - 即使没有相对较慢的正则表达式。审视自己的方式,选择最适合自己的方式。
我是 PLSQL 的新手,开始学习如何高效地编写查询。我面临着使用 Connect By 扁平化员工报告层次结构的挑战。
目前,我们在员工报告中有五个级别的层次结构,但我们的查询不应限制为 5 个级别。将来,如果我们有新的报告级别,相同的查询应该可以在不做任何更改的情况下工作。
结果集中的所有记录都应该在同一级别结束,如果经理没有向 him/her 报告的员工,那么级别 5 应该是经理本身。您可以看到下面的预期结果以便更好地理解。示例:经理 1 和经理 3
注意:为了获得更好的性能,我不想为此请求使用任何函数或子查询。
预期结果:
Level 1 Level 2 Level 3 Level 4 Level 5 **(Level 6, Level 7 ) for future**
---------- ---------- ------- ------- ------ ------ -------
President VP1 Dir1 Mgr1 Mgr1
President VP1 Dir2 Mgr2 Emp1
President VP2 Dir3 Mgr4 Emp2
President VP2 Dir4 Mgr3 Mgr3
President VP3 Dir5 Mgr5 Emp3
President VP3 Dir6 Mgr6 Emp4
President VP4 Dir7 Mgr7 Emp5
对我来说,以下看起来像你想要的:
with normalized$(super_id, emp_id) as (
select null, 'president' from dual
union all
select 'president', 'vp1' from dual
union all
select 'president', 'vp2' from dual
union all
select 'president', 'vp3' from dual
union all
select 'president', 'vp4' from dual
union all
select 'vp1', 'dir1' from dual
union all
select 'vp1', 'dir2' from dual
union all
select 'vp2', 'dir3' from dual
union all
select 'vp2', 'dir4' from dual
union all
select 'vp3', 'dir5' from dual
union all
select 'vp3', 'dir6' from dual
union all
select 'vp4', 'dir7' from dual
union all
select 'dir1', 'mgr1' from dual
union all
select 'dir2', 'mgr2' from dual
union all
select 'dir3', 'mgr4' from dual
union all
select 'dir4', 'mgr3' from dual
union all
select 'dir5', 'mgr5' from dual
union all
select 'dir6', 'mgr6' from dual
union all
select 'dir7', 'mgr7' from dual
union all
select 'mgr2', 'emp1' from dual
union all
select 'mgr4', 'emp2' from dual
union all
select 'mgr5', 'emp3' from dual
union all
select 'mgr6', 'emp4' from dual
union all
select 'mgr7', 'emp5' from dual
union all
-- note: these two are added here for testing the levels 6 and 7
select 'emp2', 'sub1' from dual
union all
select 'sub1', 'subsub1' from dual
),
denormalized$ as (
select ora_hash(emp_id) as hierarchy_id, -- note: this is just "some" row id; use whatever else you wish
sys_connect_by_path(emp_id, '|') as hierarchy
from normalized$ N
where connect_by_isleaf = 1
start with super_id is null
connect by prior emp_id = super_id
),
split$ as (
select hierarchy_id,
regexp_substr(hierarchy, '\|([^|]*)', 1, 1, null, 1) as h_lvl_1,
regexp_substr(hierarchy, '\|([^|]*)', 1, 2, null, 1) as h_lvl_2,
regexp_substr(hierarchy, '\|([^|]*)', 1, 3, null, 1) as h_lvl_3,
regexp_substr(hierarchy, '\|([^|]*)', 1, 4, null, 1) as h_lvl_4,
regexp_substr(hierarchy, '\|([^|]*)', 1, 5, null, 1) as h_lvl_5,
regexp_substr(hierarchy, '\|([^|]*)', 1, 6, null, 1) as h_lvl_6,
regexp_substr(hierarchy, '\|([^|]*)', 1, 7, null, 1) as h_lvl_7
from denormalized$
),
filled$ as (
select hierarchy_id,
h_lvl_1,
coalesce(h_lvl_2, h_lvl_1) as h_lvl_2,
coalesce(h_lvl_3, h_lvl_2, h_lvl_1) as h_lvl_3,
coalesce(h_lvl_4, h_lvl_3, h_lvl_2, h_lvl_1) as h_lvl_4,
coalesce(h_lvl_5, h_lvl_4, h_lvl_3, h_lvl_2, h_lvl_1) as h_lvl_5,
coalesce(h_lvl_6, h_lvl_5, h_lvl_4, h_lvl_3, h_lvl_2, h_lvl_1) as h_lvl_6,
coalesce(h_lvl_7, h_lvl_6, h_lvl_5, h_lvl_4, h_lvl_3, h_lvl_2, h_lvl_1) as h_lvl_7
from split$
)
select *
from filled$
;
...屈服...
HIERARCHY_ID H_LVL_1 H_LVL_2 H_LVL_3 H_LVL_4 H_LVL_5 H_LVL_6 H_LVL_7
------------ --------- ------- ------- ------- ------- ------- -------
490409852 president vp1 dir1 mgr1 mgr1 mgr1 mgr1
1220769441 president vp1 dir2 mgr2 emp1 emp1 emp1
849214331 president vp2 dir3 mgr4 emp2 sub1 subsub1
530886880 president vp2 dir4 mgr3 mgr3 mgr3 mgr3
1157603336 president vp3 dir5 mgr5 emp3 emp3 emp3
1467614544 president vp3 dir6 mgr6 emp4 emp4 emp4
523144703 president vp4 dir7 mgr7 emp5 emp5 emp5
但是,没有办法(我知道)你可以(没有 table 函数 returning sys.anyDataSet
)可能对 return 任意列数的查询,所以让我们只坚持层次结构中假定的最大级别数,如果上面的查询是 7.
注意 可以通过不同的方式完成按路径连接及其后续拆分 - 即使没有相对较慢的正则表达式。审视自己的方式,选择最适合自己的方式。