如何在 connect by 中获得具有给定 id 的完整 children 分支
How to get full children branches with given ids in connect by
我想使用给定的 child ids
获得从 parent_id = null
到 childs 的分支
select *
from company s
start with s.parent_id is null and s.id = 56
connect by prior s.id = s.parent_id
结果是元素 id: 56
的完整分支
如何 select 使用所选的 child 分支
示例:
现在的结果是:
id parent_id
56 null
57 56
58 57
59 57
60 56
61 60
我想要实现的是给定 child id: 57 select 只有那个分支
id parent_id
56 null
57 56
58 57
59 57
without not given child id:
60 56
61 60
一些简单的查询,应该能满足您的要求:
编辑:在查询中添加评论
EDIT2:最小化了 SYS_CONNECT_BY_PATH 的使用,因此更难达到它的大小限制。
WITH param AS -- this is just our parameter to be used in further subqueries (ID and regex pattern for regexp_like expression)
(
SELECT
57 AS id
,'(\s?)('||57||')(\s|\W)' AS regex
FROM
dual
)
, parent AS -- here we get the inverted hierarchy - searching for the root node of the branch where ID given as parameter exists
(
SELECT
s.*
FROM
company s
,param
CONNECT BY PRIOR s.parent_id = s.id
START WITH s.id = param.id
)
, children AS -- here we get all the children of the root node we found in parent subquery
(
SELECT
s.*
,CASE
WHEN LEVEL >= MAX(CASE WHEN s.id = param.id THEN LEVEL ELSE NULL END) OVER (PARTITION BY NULL) THEN
SYS_CONNECT_BY_PATH(s.id,' ')
ELSE NULL
END AS path -- this gives us the hierarchical path
,LEVEL AS lvl -- this gives us children's levels
,MAX(CASE WHEN s.id = param.id THEN LEVEL ELSE NULL END) OVER (PARTITION BY NULL) AS id_level -- this gives the level of the children given as a parameter
FROM
company s
,param
CONNECT BY PRIOR s.id = s.parent_id
START WITH s.id = (SELECT parent.id FROM parent WHERE parent.parent_id IS NULL)
)
-- now we select from the all children hierarchy our desired branch
SELECT
c.*
FROM
children c
,param
WHERE
1 = CASE WHEN lvl > c.id_level AND REGEXP_LIKE(c.path, param.regex) THEN 1 -- if current id is of higher level (is a child of our paremeter ID), it must have our parameter ID in it's path
WHEN lvl = c.id_level AND c.id = param.id THEN 1 -- if the level is equal to our parameter's ID's leve, it has to be our paremeter
WHEN lvl < c.id_level AND EXISTS(SELECT 1 FROM parent WHERE parent.id = c.id) THEN 1 -- if current level is lower (may be a parent of our parmeter ID) it has to exists in the reverse hierarchy (thus, must be a parent or grandparent etc. of our paremter node)
ELSE 0
END
顺便说一句。在阅读了 Carlo Sirna 的解决方案后,我发现他的解决方案更好:)
这个适用于任何可能的树深度,并且不使用正则表达式或字符串连接。应该很容易理解:
with
all_children_of_57 as
(
-- all nodes that can be reached by starting a recursive descent from node 57
select id
from company s
start with s.id = 57
connect by prior s.id = s.parent_id
),
all_ancestors_of_57 as
(
-- all ANCESTORS that can be reached by walking up the tree (FROM CHILD TO PARENT),
-- starting from node 57 (this is a linear recursion)
select id
from company s
start with s.id = 57
connect by s.id = prior s.parent_id
),
nodes_in_branch as
(
-- we are interested only in nodes extracted from the above two queries
select *
from company
where id in (select id from all_children_of_57)
or id in (select id from all_ancestors_of_57)
)
-- we do the recursion on the result of nodes_in_branch
select *
from nodes_in_branch s
start with s.parent_id is null
connect by prior s.id = s.parent_id
我想使用给定的 child ids
获得从parent_id = null
到 childs 的分支
select *
from company s
start with s.parent_id is null and s.id = 56
connect by prior s.id = s.parent_id
结果是元素 id: 56
的完整分支如何 select 使用所选的 child 分支
示例:
现在的结果是:
id parent_id
56 null
57 56
58 57
59 57
60 56
61 60
我想要实现的是给定 child id: 57 select 只有那个分支
id parent_id
56 null
57 56
58 57
59 57
without not given child id:
60 56
61 60
一些简单的查询,应该能满足您的要求:
编辑:在查询中添加评论
EDIT2:最小化了 SYS_CONNECT_BY_PATH 的使用,因此更难达到它的大小限制。
WITH param AS -- this is just our parameter to be used in further subqueries (ID and regex pattern for regexp_like expression)
(
SELECT
57 AS id
,'(\s?)('||57||')(\s|\W)' AS regex
FROM
dual
)
, parent AS -- here we get the inverted hierarchy - searching for the root node of the branch where ID given as parameter exists
(
SELECT
s.*
FROM
company s
,param
CONNECT BY PRIOR s.parent_id = s.id
START WITH s.id = param.id
)
, children AS -- here we get all the children of the root node we found in parent subquery
(
SELECT
s.*
,CASE
WHEN LEVEL >= MAX(CASE WHEN s.id = param.id THEN LEVEL ELSE NULL END) OVER (PARTITION BY NULL) THEN
SYS_CONNECT_BY_PATH(s.id,' ')
ELSE NULL
END AS path -- this gives us the hierarchical path
,LEVEL AS lvl -- this gives us children's levels
,MAX(CASE WHEN s.id = param.id THEN LEVEL ELSE NULL END) OVER (PARTITION BY NULL) AS id_level -- this gives the level of the children given as a parameter
FROM
company s
,param
CONNECT BY PRIOR s.id = s.parent_id
START WITH s.id = (SELECT parent.id FROM parent WHERE parent.parent_id IS NULL)
)
-- now we select from the all children hierarchy our desired branch
SELECT
c.*
FROM
children c
,param
WHERE
1 = CASE WHEN lvl > c.id_level AND REGEXP_LIKE(c.path, param.regex) THEN 1 -- if current id is of higher level (is a child of our paremeter ID), it must have our parameter ID in it's path
WHEN lvl = c.id_level AND c.id = param.id THEN 1 -- if the level is equal to our parameter's ID's leve, it has to be our paremeter
WHEN lvl < c.id_level AND EXISTS(SELECT 1 FROM parent WHERE parent.id = c.id) THEN 1 -- if current level is lower (may be a parent of our parmeter ID) it has to exists in the reverse hierarchy (thus, must be a parent or grandparent etc. of our paremter node)
ELSE 0
END
顺便说一句。在阅读了 Carlo Sirna 的解决方案后,我发现他的解决方案更好:)
这个适用于任何可能的树深度,并且不使用正则表达式或字符串连接。应该很容易理解:
with
all_children_of_57 as
(
-- all nodes that can be reached by starting a recursive descent from node 57
select id
from company s
start with s.id = 57
connect by prior s.id = s.parent_id
),
all_ancestors_of_57 as
(
-- all ANCESTORS that can be reached by walking up the tree (FROM CHILD TO PARENT),
-- starting from node 57 (this is a linear recursion)
select id
from company s
start with s.id = 57
connect by s.id = prior s.parent_id
),
nodes_in_branch as
(
-- we are interested only in nodes extracted from the above two queries
select *
from company
where id in (select id from all_children_of_57)
or id in (select id from all_ancestors_of_57)
)
-- we do the recursion on the result of nodes_in_branch
select *
from nodes_in_branch s
start with s.parent_id is null
connect by prior s.id = s.parent_id