You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Oracle CONNECT BY实现无环有向图根路径查询的重复行问题

问题分析与解决方案

你的CONNECT BY查询出现重复行,核心问题出在主查询中多余的LEFT JOIN edge

当根节点(比如ID=1的KBR)有多个出边时,LEFT JOIN edge会让这个根节点生成多条重复的起始行(对应每条出边),而START WITH会对这些重复行分别处理,最终导致根节点的零长度路径(/1)被重复输出。

另外,你的CONNECT BY条件逻辑也写反了:PRIOR hier.child = parent.id是从子节点回溯到父节点的逻辑,而我们需要的是从父节点向下遍历到子节点,这也会导致层级遍历的逻辑混乱。


修正后的查询代码

SELECT 
    n.id,
    n.name,
    CONNECT_BY_ROOT n.id AS root_id,
    LEVEL AS lvl,
    SYS_CONNECT_BY_PATH(n.id, '/') AS path
FROM node n
START WITH NOT EXISTS (SELECT 1 FROM edge h WHERE h.child = n.id)
CONNECT BY PRIOR n.id = edge.parent AND edge.child = n.id

或者更简洁的写法(利用Oracle层级查询的关联语法):

SELECT 
    n.id,
    n.name,
    CONNECT_BY_ROOT n.id AS root_id,
    LEVEL AS lvl,
    SYS_CONNECT_BY_PATH(n.id, '/') AS path
FROM node n
LEFT JOIN edge e ON n.id = e.child
START WITH NOT EXISTS (SELECT 1 FROM edge h WHERE h.child = n.id)
CONNECT BY PRIOR n.id = e.parent

关键修改点说明

  • 移除主查询中不必要的LEFT JOIN
    不需要提前将nodeedge表做JOIN,层级关系完全可以通过CONNECT BY子句来关联,避免根节点因为多出边产生重复起始行。

  • 修正CONNECT BY的层级逻辑
    PRIOR n.id = e.parent表示“上一层级的节点ID等于当前节点的父节点ID”,这和你之前递归CTE的逻辑一致,实现从根节点向下遍历子节点的需求。

  • 保留START WITH的根节点判断
    依然用NOT EXISTS (SELECT 1 FROM edge h WHERE h.child = n.id)来筛选无入边的根节点,确保遍历的起始点正确。

运行修正后的查询,就能得到你预期的10行结果,不会再出现重复的根节点路径。

内容的提问来源于stack exchange,提问作者Sebastian Stern

火山引擎 最新活动