Oracle connect by 查找子、祖先对
Oracle connect by to find child, ancestor pairs
我正在尝试编写查询以获取所有节点及其祖先。数据库存储一棵树(节点及其 children/parents)。我知道 connect by 可以给出所有的祖先,当加上 start with 子句时,你可以获得单个节点的所有祖先。
这里有一个简单的例子来说明我要做什么。
节点边table:
+---------+-----------+
|child_id |parent_id |
+---------+-----------+
|2 |1 |
|3 |2 |
|4 |2 |
|5 |4 |
+---------+-----------+
我写的查询是:
select parent_id, child_id
from edges
start with child_id = 5
connect by child_id = prior parent_id
给出:
+---------+-----------+
|child_id |parent_id |
+---------+-----------+
|2 |1 |
|4 |2 |
|5 |4 |
+---------+-----------+
我要找的是这样的:
+---------+-----------+
|child_id |parent_id |
+---------+-----------+
|2 |1 |
|3 |2 |
|3 |1 |
|4 |2 |
|4 |1 |
|5 |4 |
|5 |2 |
|5 |1 |
+---------+-----------+
所以每个节点都有一条记录,记录了它的每个祖先,一直到根。我在构建查询以获得此结果时遇到了一些麻烦。有什么建议吗?
谢谢,
麦坎格斯
以下查询解决了您的问题:
with tree (childid, parentid)
as
(select child_id, parent_id from
edges
union all
select t.childid, g.parent_id
from tree t
join edges g
on t.parentid = g.child_id)
select * from tree
order by childid, parentid desc
使用CONNECT_BY_ROOT
运算符:
WITH edges (child_id, parent_id) AS (
SELECT 2, 1 FROM DUAL UNION ALL
SELECT 3, 2 FROM DUAL UNION ALL
SELECT 4, 2 FROM DUAL UNION ALL
SELECT 5, 4 FROM DUAL
)
SELECT
child_id, CONNECT_BY_ROOT parent_id parent_id
FROM
edges
CONNECT BY
PRIOR child_id = parent_id
ORDER BY
child_id, parent_id DESC;
我认为 "start with" 没有达到您的预期。这将限制您的根行,这就是您获得有限结果集的原因。您还希望 CONNECT_BY_ROOT 不仅获得根行的 child_id,而且获得 child_id。免责声明:我不是 oracle 大师,我只是有一些时间。
SYS_CONNECT_BY_PATH 只是额外信息。
select CONNECT_BY_ROOT child_id "CHILD_ID", parent_id, SYS_CONNECT_BY_PATH(child_id, '/') "PATH"
from edges
connect by child_id = prior parent_id;
结果:
CHILD_ID PARENT_ID PATH
2 1 /2
3 2 /3
3 1 /3/2
4 2 /4
4 1 /4/2
5 4 /5
5 2 /5/4
5 1 /5/4/2
查看 docs。
我正在尝试编写查询以获取所有节点及其祖先。数据库存储一棵树(节点及其 children/parents)。我知道 connect by 可以给出所有的祖先,当加上 start with 子句时,你可以获得单个节点的所有祖先。
这里有一个简单的例子来说明我要做什么。
节点边table:
+---------+-----------+
|child_id |parent_id |
+---------+-----------+
|2 |1 |
|3 |2 |
|4 |2 |
|5 |4 |
+---------+-----------+
我写的查询是:
select parent_id, child_id
from edges
start with child_id = 5
connect by child_id = prior parent_id
给出:
+---------+-----------+
|child_id |parent_id |
+---------+-----------+
|2 |1 |
|4 |2 |
|5 |4 |
+---------+-----------+
我要找的是这样的:
+---------+-----------+
|child_id |parent_id |
+---------+-----------+
|2 |1 |
|3 |2 |
|3 |1 |
|4 |2 |
|4 |1 |
|5 |4 |
|5 |2 |
|5 |1 |
+---------+-----------+
所以每个节点都有一条记录,记录了它的每个祖先,一直到根。我在构建查询以获得此结果时遇到了一些麻烦。有什么建议吗?
谢谢, 麦坎格斯
以下查询解决了您的问题:
with tree (childid, parentid)
as
(select child_id, parent_id from
edges
union all
select t.childid, g.parent_id
from tree t
join edges g
on t.parentid = g.child_id)
select * from tree
order by childid, parentid desc
使用CONNECT_BY_ROOT
运算符:
WITH edges (child_id, parent_id) AS (
SELECT 2, 1 FROM DUAL UNION ALL
SELECT 3, 2 FROM DUAL UNION ALL
SELECT 4, 2 FROM DUAL UNION ALL
SELECT 5, 4 FROM DUAL
)
SELECT
child_id, CONNECT_BY_ROOT parent_id parent_id
FROM
edges
CONNECT BY
PRIOR child_id = parent_id
ORDER BY
child_id, parent_id DESC;
我认为 "start with" 没有达到您的预期。这将限制您的根行,这就是您获得有限结果集的原因。您还希望 CONNECT_BY_ROOT 不仅获得根行的 child_id,而且获得 child_id。免责声明:我不是 oracle 大师,我只是有一些时间。
SYS_CONNECT_BY_PATH 只是额外信息。
select CONNECT_BY_ROOT child_id "CHILD_ID", parent_id, SYS_CONNECT_BY_PATH(child_id, '/') "PATH"
from edges
connect by child_id = prior parent_id;
结果:
CHILD_ID PARENT_ID PATH
2 1 /2
3 2 /3
3 1 /3/2
4 2 /4
4 1 /4/2
5 4 /5
5 2 /5/4
5 1 /5/4/2
查看 docs。