通过兄弟链接列表的Oracle DB Order Tree兄弟姐妹

时间:2014-03-15 00:06:13

标签: sql oracle tree hierarchy

我打算将树对象存储在数据库表中。这是我的架构:

CREATE TABLE Nodes (
  ID number(11) NOT NULL,
  dataID number(11) NOT NULL,
  parentNode number(11),
  siblingNode number(11),
);

假设我有三个树A,B,C,其根节点作为父节点为NULL。我想从节点表中选择所有记录,这些记录按照它们所属的树分组,排序类似于深度优先搜索,其中兄弟姐妹按其各自的链接列表排序。例如,如果D,E和F是节点A的子节点,并且预期的顺序是F-> E-> D,那么F将具有兄弟节点NULL,E将具有作为兄弟节点和D的F的ID。将E的ID作为siblingNode。

到目前为止,我已经完成了一个常见的CONNECT BY查询,我发现有一个ORDER SIBLINGS BY子句,但这只能通过对升序或降序值进行排序,而不是使用链接列表。到目前为止,我的查询只是简单地对ID进行排序,并没有考虑兄弟联系(并且可以保证兄弟姐妹的进入顺序。)

SELECT ID, connect_by_root(ID) root
FROM Nodes
START WITH parentNode IS NULL
CONNECT BY PRIOR ID = parentNode
ORDER SIBLINGS BY ID ASC;

最终我想使用LISTAGG从数据函数创建一个字符串,以在我的树上创建一个视图。该视图每个树(A,B,C)有一行,其中包含表示波兰表示法中的树的字符串。到目前为止,我有:

SELECT DISTINCT connect_by_root(ID) root, LISTAGG(dataString(ID), ' ') WITHIN GROUP (ORDER BY ID ASC) OVER (PARTITION BY connect_by_root(ID)) polish
FROM Nodes
START WITH parentNode IS NULL
CONNECT BY PRIOR ID = parentNode
ORDER SIBLINGS BY ID ASC;

我是Oracle DB的新手,并且不知道是否有更好的方法来执行上述任何操作。我欢迎任何评论,特别想知道如何通过他们的联系订购兄弟姐妹。

示例数据:

ID:1;数据ID =>' - &#39 ;; parentNode:null; siblingNode:null;
ID:2;数据ID =>' 1&#39 ;; parentNode:1; siblingNode:3;
ID:3;数据ID =>' 6&#39 ;; parentNode:1; siblingNode:null;
ID:4;数据ID =>' *&#39 ;; parentNode:null; siblingNode:null;
ID:5;数据ID =>' 8&#39 ;; parentNode:4; siblingNode:null;
ID:6;数据ID =>' 8&#39 ;; parentNode:4; siblingNode:5;

期望的输出:

ID:1; POLISH:' + 6 1'
ID:4; POLISH:' * 8 8'

ORDER SIBLINGS BY ID ASC的问题是第一个输出将返回' - 1 6'这与' - 6 1'不同。

我已经创建了一个示例数据来证明问题。此外,由于某种原因,它不允许我使用ORDER SIBLINGS BY子句...... http://sqlfiddle.com/#!4/6ec46/4

2 个答案:

答案 0 :(得分:1)

如果我正确理解您的问题,您希望Hierarchical Query返回波兰表示法(叶节点)及其相应的节点 - >根节点路径。然后,您将使用此查询提供波兰表示法关系的视图。

您可以使用LISTAGG而不是SYS_CONNECT_BY_PATH函数,并使用空格或任何其他有效的VARCHAR作为分隔符吗?查询看起来如下所示:

SELECT DISTINCT ID AS root, SYS_CONNECT_BY_PATH(dataString(ID), ' ') POLISH
FROM Nodes
START WITH parentNode IS NULL
CONNECT BY PRIOR ID = parentNode
ORDER SIBLINGS BY ID ASC;

如果我误解了您的问题,请告诉我,我会更新我的答案。

答案 1 :(得分:1)

我设法生成了一个查询,通过加入由siblingNode连接的第二个查询并按兄弟级别LEVEL排序,给出了我预期的结果:

SELECT DISTINCT wut.root,
   LISTAGG(wut.data, ' ')
    WITHIN GROUP (ORDER BY wut.polishOrder)
    OVER (PARTITION BY wut.root) polish
FROM        
( SELECT connect_by_root(n.ID) root, data, ROWNUM polishOrder
 FROM Nodes n
 JOIN
 (SELECT m.ID, LEVEL l
  FROM Nodes m
  START WITH m.siblingNode IS NULL
  CONNECT BY PRIOR m.ID = m.siblingNode) mm
 ON n.ID = mm.ID
     START WITH n.parentNode IS NULL
     CONNECT BY PRIOR n.ID = n.parentNode
     ORDER SIBLINGS BY mm.l
) wut

http://sqlfiddle.com/#!4/94facf/25