Посмотрите на свою структуру данных. У вас есть одна строка, представляющая DMID 1, PMID 1, которую вы хотите отобразить в виде двух отдельных строк в своем дереве. Каким-то образом вам нужно создать дополнительные строки в вашем наборе результатов для представления этих промежуточных узлов. Хороший способ сделать это - использовать GROUPING SETS
.
Итак, мы будем объединять две таблицы и GROUP BY GROUPING SETS(...)
таким образом, чтобы получить объединенную иерархию всех узлов, будь то узлы DM, PM или DEV.
Получив это, мы просто сделаем простой запрос CONNECT BY
в объединенной иерархии.
Ниже я приведу работающую реализацию этого плана, но сначала позвольте мне сказать, что если вам часто приходится делать такие вещи, серьезно подумайте о том, что, возможно, ваша модель данных не разработана должным образом.
Вот запрос с комментариями. Эта версия даст вам дерево справа от вашего поста, то есть того, которое пропускает уровни TL
. Простая модификация дала бы дерево слева вместо этого ... было неясно, какой именно вам нужен (извините).
-- First provide data to simulate your V_Mgmt table...
With V_Mgmt ( DMid, PMId, TLId ) AS (
SELECT 1, 1, 1 FROM DUAL UNION ALL
SELECT 1, 1, 2 FROM DUAL UNION ALL
SELECT 1, 2, 3 FROM DUAL UNION ALL
SELECT 2, 3, 4 FROM DUAL UNION ALL
SELECT 2, 3, 5 FROM DUAL UNION ALL
SELECT 2, 4, 6 FROM DUAL ),
-- ... and your T_ProjLevels table
T_ProjLevels (TLId, DevId, ParentDevId) AS (
SELECT 1, 1, 0 FROM DUAL UNION ALL
SELECT 1, 2, 1 FROM DUAL UNION ALL
SELECT 1, 3, 1 FROM DUAL UNION ALL
SELECT 2, 4, 0 FROM DUAL UNION ALL
SELECT 2, 5, 4 FROM DUAL UNION ALL
SELECT 2, 6, 4 FROM DUAL UNION ALL
SELECT 2, 7, 6 FROM DUAL UNION ALL
SELECT 3, 8, 0 FROM DUAL UNION ALL
SELECT 3, 9, 0 FROM DUAL UNION ALL
SELECT 4, 10, 0 FROM DUAL UNION ALL
SELECT 4, 11, 0 FROM DUAL UNION ALL
SELECT 4, 12, 11 FROM DUAL ),
-- Next, merge them together
-- (A) using GROUPING_SETS to create extra rows for the DM, PM, but not the TL-level nodes
-- (B) combining DM, PM, (but not TL), and DEV ids into a common set of "node", "parent_node", and "node_name" columns
merged_hierarchy ( node, parent_node, node_name ) AS (
SELECT rtrim(m.dmid || '.' || m.pmid || '.' || pl.devid,'.') node,
rtrim(
case
when grouping(m.pmid) = 1 then NULL
when grouping(m.tlid) = 1 then to_char(m.dmid)
when grouping(pl.devid) = 1 then m.dmid || '.' || m.pmid
else
m.dmid || '.' || m.pmid || '.' || nullif(pl.parentdevid,0) end,'.') parent_node,
case when grouping(pl.devid) = 0 THEN 'DEV' || pl.devid
when grouping(m.tlid) = 0 THEN 'TL' || m.tlid
when grouping(m.pmid) = 0 THEN 'PM' || m.pmid
when grouping(m.dmid) = 0 THEN 'DM' || m.dmid
end node_name
from v_mgmt m
left join t_projlevels pl on pl.tlid = m.tlid
group by grouping sets ( ( m.dmid ), ( m.dmid, m.pmid), (m.dmid, m.pmid, m.tlid, pl.devid, pl.parentdevid ) )
)
-- Finally, query the merged hierarchy as a straight-forward CONNECT BY query
SELECT lpad(' ',5*(level-1),' ') || node_name output
FROM merged_hierarchy
START WITH parent_node IS NULL
CONNECT BY parent_node = prior node
-- Exclude the outer-joined rows from T_ProjLevels...
AND node_name != 'DEV';
+--------------------------+
| OUTPUT |
+--------------------------+
| DM1 |
| PM1 |
| DEV1 |
| DEV2 |
| DEV3 |
| DEV4 |
| DEV5 |
| DEV6 |
| DEV7 |
| PM2 |
| DEV8 |
| DEV9 |
| DM2 |
| PM3 |
| DEV10 |
| DEV11 |
| DEV12 |
| PM4 |
+--------------------------+