如何使用Connect by Prior同时查询实体的父节点与子节点?
解决方法:同时获取指定节点的父节点与子节点
要同时拿到id=2的所有父节点(含祖先)和子节点(含子孙),你可以通过两种方式实现,基于Oracle的CONNECT BY语法:
方法1:合并两个单向遍历查询
原语句是从id=2向下遍历所有子节点(包括自身),如果要获取父节点,我们需要反过来向上遍历所有祖先节点,然后用UNION合并两个结果(自动去重,避免重复出现id=2的记录):
-- 向下查询:获取id=2的所有子节点(含自身) SELECT * FROM myTable tab CONNECT BY PRIOR tab.id = tab.child_id START WITH tab.id = 2 UNION -- 向上查询:获取id=2的所有父节点(含自身) SELECT * FROM myTable tab CONNECT BY tab.id = PRIOR tab.child_id START WITH tab.id = 2;
原理说明
- 第一个
CONNECT BY PRIOR tab.id = tab.child_id:表示"当前节点的id等于下一个节点的child_id",也就是从start节点往下找所有子节点。 - 第二个
CONNECT BY tab.id = PRIOR tab.child_id:表示"当前节点的id等于上一个节点的child_id",也就是从start节点往上找所有父节点/祖先。 UNION会自动合并两个结果集,并去掉重复的记录(因为start节点会在两个查询中都出现)。
方法2:使用双向遍历+NOCYCLE关键字
如果你想用单条查询实现,可以通过OR把双向遍历的条件合并,同时加上NOCYCLE防止出现循环引用导致的无限遍历(比如表中存在A→B→A的循环关系时):
SELECT * FROM myTable tab CONNECT BY NOCYCLE (tab.id = PRIOR tab.child_id OR PRIOR tab.id = tab.child_id) START WITH tab.id = 2;
注意事项
- 这种方式会一次性返回所有相关节点,但如果你的树形结构存在循环引用,必须加上
NOCYCLE,否则查询会报错。 - 你可以额外添加
LEVEL列来区分节点的层级关系,比如SELECT *, LEVEL FROM ...,方便判断是父节点还是子节点。
内容的提问来源于stack exchange,提问作者Ananta




