Oracle 分层路径作为单独的行

Oracle hierarchical path as separate row

我有一个 table 如下所示:

ID     PARENT_ID
---    ----------  
  1     null
  2     1
  3     2
  4     2
  5     4
  6     4
  7     1
  8     7
  9     1
 10     9
 11     10
 12     9
 13     null
 14     13                 

我想查询这样的结果:

  ID | PARENT_ID
-----+-----------
   1 |   1
   2 |   1
   2 |   2
   3 |   1
   3 |   2
   3 |   3
   4 |   1
   4 |   2
   4 |   4
   5 |   1
   5 |   2
   5 |   4
   5 |   5
   ...     

我使用了 Oracle connected by root 并得到了这个结果:

 ID PATH
--- -----------
 1  1
 2  1-2
 3  1-2-3
 4  1-2-4
 5  1-2-4-5
 ....

但这不是我想要的。

是否有另一种方法可以在不通过根连接的情况下获得结果(在标准 SQL 中更受欢迎),从 table 获得相同的结果?

谁能帮帮我?

注意:我使用的是Oracle数据库

谢谢

第一步是进行查询,为您生成特定节点上方的所有父节点。

下面是此类查询的示例:

    select * from
(SELECT parent_id
FROM test
START WITH ID = 4
CONNECT BY ID = PRIOR PARENT_ID) temp
where parent_id is not null

UNION

select ID from test where ID = 4 ;

在上述情况下,我们从节点 4 开始。

下一步是使用此查询,并使用另一个查询来获取所有节点的结果。

(即将制作)

最终解决方案

create table test(
  id int,
  parent_id int
);

insert into test values (1, null);
insert into test values (2,1);
insert into test values (3,2);
insert into test values (4,2);

select distinct ID, parent_id from
  (
SELECT a.parent_id as aParent, b.parent_id as bParent, b.id as ID, a.id as parent_id
FROM test a, test b
START WITH a.ID = b.id
CONNECT BY a.ID = PRIOR a.PARENT_ID
  ) temp
  where not (aParent is not null AND bParent is null)
order by id, parent_id;

优化

  SELECT distinct b.id as ID, a.id as parent_id
    FROM test a, test b
     where not (a.parent_id is not null and b.parent_id is null )
    START WITH a.ID = b.id
    CONNECT BY a.ID = PRIOR a.PARENT_ID order by id, parent_id;;

布尔代数简化

   SELECT distinct
  findNodesAboveMe.id as ID,
  pathFollowing.id    as parent_id
FROM
  test pathFollowing,
  test findNodesAboveMe
where
  pathFollowing.parent_id is null
  OR findNodesAboveMe.parent_id is not null START WITH pathFollowing.ID = findNodesAboveMe.id CONNECT BY pathFollowing.ID = PRIOR pathFollowing.PARENT_ID
order by
  id,
  parent_id;

修复 Null 父项

select id, parent_id from
  (
    (SELECT DISTINCT
       findNodesAboveMe.id              AS ID,
       CASE WHEN pathFollowing.parent_id IS NULL
         THEN pathFollowing.id
       ELSE pathFollowing.parent_id END AS parent_id
     FROM
       test pathFollowing,
       test findNodesAboveMe
     WHERE
       findNodesAboveMe.parent_id IS NOT NULL
     START WITH pathFollowing.ID = findNodesAboveMe.id CONNECT BY pathFollowing.ID = PRIOR pathFollowing.PARENT_ID
    )
    UNION
    SELECT
      id,
      id AS parent_id
    FROM test
  ) order by id, parent_id
;

更新

select
  distinct bid as ID, aid as parent_id

  from
    (
      SELECT DISTINCT
        a.id as aid,
        a.parent_id as aparentid,
        b.id as bid,
        b.parent_id as bparentid,

        ltrim(sys_connect_by_path(a.id, ','), ',') AS pth
      FROM test a, test b
      WHERE NOT
            (a.parent_id IS NOT NULL AND b.parent_id IS NULL)
      START WITH a.ID = b.id
      CONNECT BY a.ID = PRIOR a.PARENT_ID
    ) temp
  where ( pth like bid or  pth like bid || ','|| bparentid || '%' )
 order by ID, parent_id;