3

我有一个表名,它有两列,一列是p,第二列是ch

p       ch 
-------------
1       2                   
1       3 
1       4 
2       5 
2       6 
7       8 
9       10 
11      12 
6       13 
13      14 
14      15 
14      16

我想要的输出是所有链接到父母的孩子。例如,如果我给“1”作为输入,我必须找到所有父元素和子元素,在这种情况下,1 是 2、3、4 的父元素,2 是 5 的父元素,依此类推......在这种情况下,我需要每个链接的子元素和父元素本身,如下所述:

ParentChilds
------------
1
2
3
4
5
6
13
14
15
16

下面是我写的查询,我想确认它是最好的解决方案,或者我们可以做得更好,因为我的表中有大量数据:

with LinkedAccounts (p, ch, orig_recur, dest_recur, lvl) as (
            select n.p
    , n.ch
    , 1 orig_recur
     , case n.p
           when 1 then ch
                   else p
        end dest_recur
     , 1 lvl
   from tree n
 where n.p = 1
   or n.ch = 1 union all
select n.p
     , n.ch
    , LinkedAccounts.dest_recur orig_recur
     , case n.p
         when LinkedAccounts.dest_recur then n.ch
                           else n.p
       end dest_recur
     , LinkedAccounts.lvl + 1 lvl
  from LinkedAccounts
  join tree n
        on (n.p = LinkedAccounts.dest_recur and n.ch != LinkedAccounts.orig_recur)
        or (n.ch = LinkedAccounts.dest_recur and n.p != LinkedAccounts.orig_recur)
)
 search breadth first by orig_recur, dest_recur set ordering
cycle ch,
 p set is_cycle to '1' default '0'   select distinct p    from LinkedAccounts    union     Select Distinct ch    from LinkedAccounts;
4

2 回答 2

4

使用分层查询:

SQL小提琴

Oracle 11g R2 模式设置

CREATE TABLE TREE ( p, ch ) AS
          SELECT  1,  2 FROM DUAL
UNION ALL SELECT  1,  3 FROM DUAL
UNION ALL SELECT  1,  4 FROM DUAL
UNION ALL SELECT  2,  5 FROM DUAL
UNION ALL SELECT  2,  6 FROM DUAL
UNION ALL SELECT  7,  8 FROM DUAL
UNION ALL SELECT  9, 10 FROM DUAL
UNION ALL SELECT 11, 12 FROM DUAL
UNION ALL SELECT  6, 13 FROM DUAL
UNION ALL SELECT 13, 14 FROM DUAL
UNION ALL SELECT 14, 15 FROM DUAL
UNION ALL SELECT 14, 16 FROM DUAL
UNION ALL SELECT  2,  1 FROM DUAL;

查询 1

SELECT     p AS ParentChilds
FROM       TREE
START WITH p = 1
CONNECT BY NOCYCLE PRIOR ch = p
UNION
SELECT     ch
FROM       TREE
START WITH p = 1
CONNECT BY NOCYCLE PRIOR ch = p
UNION
SELECT     p
FROM       TREE
START WITH p = 1
CONNECT BY NOCYCLE ch = PRIOR p

结果

| PARENTCHILDS |
|--------------|
|            1 |
|            2 |
|            3 |
|            4 |
|            5 |
|            6 |
|           13 |
|           14 |
|           15 |
|           16 |

查询 2

SELECT     p AS ParentChilds
FROM       TREE
START WITH p = 6
CONNECT BY NOCYCLE PRIOR ch = p
UNION
SELECT     ch
FROM       TREE
START WITH p = 6
CONNECT BY NOCYCLE PRIOR ch = p
UNION
SELECT     p
FROM       TREE
START WITH p = 6
CONNECT BY NOCYCLE ch = PRIOR p

结果

| PARENTCHILDS |
|--------------|
|            1 |
|            2 |
|            6 |
|           13 |
|           14 |
|           15 |
|           16 |
于 2015-06-23T07:24:42.883 回答
1

这种方法可能更容易阅读,因为它使用更传统的递归 cte 方法,从根开始并将每个父级连接到其子级。根节点被识别为那些本身没有父节点的节点(where not exists)。

with LinkedAccounts(topRoot, parent, child, lvl)
as 
    (
        select r.p as topRoot, r.p as parent, r.ch as child, 1 as lvl
            from tree r
            where not exists
            (
                select 1 from tree t where r.p = t.ch
            )

        union all

        select la.topRoot
            , ch.p
            , ch.ch
            , la.lvl + 1
        from LinkedAccounts la
            inner join tree ch
            on ch.p = la.child
    ),
    ParentAndChild as
    (
        select topRoot, parent as node, lvl from LinkedAccounts

        union all

        select topRoot, child as node, lvl from LinkedAccounts
    )
    select distinct node
        from ParentAndChild
        where topRoot = 1
        order by node ASC;

SqlFiddle 在这里

顺便说一句,您的层次结构中的命名约定是不寻常的 -ch通常是nodeid(但parent会是 parent / parentid) - 然后这将为节点建模,允许节点上的其他列。乍一看,您似乎是在建模连接关系本身,而不是节点?

于 2015-06-23T05:28:02.847 回答