给定任何节点作为输入的Oracle SQL完整层次结构

问题描述 投票:0回答:2

我想在Oracle SQL数据库中创建一个完整的层次结构搜索查询。我有一张名为“item”的下表。

id   name  parent_id
1    A     NULL
2    B     1
3    C     2
4    D     3
5    E     2

输入是来自id列的任何给定id。它应该找到所有这个id的孩子,他们的孩子。父母和他们的父母一样。目前我有以下查询:

select distinct m.id, m.parent_id
    from item m
connect by prior m.id = m.parent_id
    start with m.parent_id IN (
        select m.parent_id
        from item m
        connect by m.id = prior m.parent_id
    start with m.id = 3
    union
    select m.parent_id
        from item m
    where m.parent_id = 3);

目前它似乎只是工作,没有选择没有父(parent_id列为空)的父。否则它似乎正在起作用。此外,如果我的查询可以简化,我也会很感激。

编辑

我想我通过以下查询得到了理想的结果:

select m.id
    from item m
    start with m.id in (
        select m.id
        from item m
        where connect_by_isleaf = 1
        start with m.id = 3
        connect by m.id = prior m.parent_id
    )
    connect by m.parent_id = prior m.id;

现在我有下一个问题。从m.id = 3开始。问题是我想从整个查询中创建一个视图。但是当m.id值从查询更改为查询时,我无法将其添加为参数。还有可能用m.id = 3注释掉,然后它将返回所有项目之间的所有层次结构。有没有办法创建一些连接?例如:我会查询所有项目的所有关系,然后通过某些条件得到某些项目关系。

sql oracle hierarchical-data
2个回答
0
投票

如果要将其用作视图,可以执行以下操作:

WITH rek AS (SELECT item.id
                  , item.name
                  , connect_by_root item.id root_id
               FROM item
              START WITH parent_id IS null
            CONNECT BY NOCYCLE parent_id = PRIOR id)
SELECT startItem.id startId
     , startItem.name startName
     , childItem.id childID
     , childItem.name childName
  FROM rek startItem
  JOIN rek childItem
  USING (root_id)
-- WHERE startItem.id = 3 -- This would be done from outside the view

子查询rek将树的所有兄弟与根元素连接起来。然后,您只需要使用此查询两次,并通过根元素连接它以获取通过父子关系连接的所有元素。

如果要减少结果集,可以使用SYS_CONNECT_BY_PATH执行此操作:

WITH rek AS (SELECT item.id
                  , item.name
                  , connect_by_root item.id root_id
                  , SYS_CONNECT_BY_PATH(item.id, '/') path
               FROM item
              START WITH parent_id IS null
            CONNECT BY NOCYCLE parent_id = PRIOR id)
SELECT startItem.id startId
     , startItem.name startName
     , childItem.id childID
     , childItem.name childName
     , childItem.path 
  FROM rek startItem
  JOIN rek childItem
    ON startItem.root_id = childItem.root_id
    AND (startItem.path LIKE childItem.path||'/%'
      OR childItem.path LIKE startItem.path||'/%'
      OR childItem.id = startItem.id)

例如,这将只为您提供起点的孩子和父母以及其他叶子的条目。


0
投票

Oracle安装程序:

CREATE TABLE item ( id, name, parent_id ) AS
  SELECT 1, 'A', NULL FROM DUAL UNION ALL
  SELECT 2, 'B',    1 FROM DUAL UNION ALL
  SELECT 3, 'C',    2 FROM DUAL UNION ALL
  SELECT 4, 'D',    3 FROM DUAL UNION ALL
  SELECT 5, 'E',    2 FROM DUAL;

你可以使用以下方式获取物品及其所有祖先:

SELECT *
FROM   item
START WITH id = 2
CONNECT BY PRIOR parent_id = id

你可以使用以下方法获取项目的所有后代:

SELECT *
FROM   item
START WITH parent_id = 2
CONNECT BY PRIOR id = parent_id

你可以使用UNION ALL将两者结合起来。然而,这会使匹配的项目先于祖先按顺序增加祖先,然后按顺序降低祖先的顺序...这可能会令人困惑。

因此,您可以对查询重新排序,以便将它们置于一致的顺序中:

SELECT *
FROM   (
  SELECT *
  FROM   item
  START WITH id = 2
  CONNECT BY PRIOR parent_id = id
  ORDER BY LEVEL DESC
)
UNION ALL
SELECT *
FROM   (
  SELECT *
  FROM   item
  START WITH parent_id = 2
  CONNECT BY PRIOR id = parent_id
  ORDER SIBLINGS BY name
);

输出:

ID NAME PARENT_ID
-- ---- ---------
1  A    -
2  B    1
3  C    2
4  D    3
5  E    2
© www.soinside.com 2019 - 2024. All rights reserved.