gpt4 book ai didi

sql - Oracle 对非分层数据的分层查询

转载 作者:行者123 更新时间:2023-12-03 22:39:45 25 4
gpt4 key购买 nike

我在 Oracle 表中包含数据,该表被组织为可以包含循环的图形(参见示例)。

     CREATE TABLE T (parent INTEGER, child INTEGER)
AS select 1 parent, 2 child from dual
union all select 1 parent, 8 child from dual
union all select 2 parent, 3 child from dual
union all select 2 parent, 4 child from dual
union all select 2 parent, 8 child from dual
union all select 3 parent, 4 child from dual
union all select 3 parent, 6 child from dual
union all select 4 parent, 5 child from dual
union all select 5 parent, 8 child from dual
union all select 6 parent, 5 child from dual
union all select 7 parent, 3 child from dual
union all select 7 parent, 5 child from dual
union all select 8 parent, 6 child from dual

Data sample

我的目标是获得 作为节点 X 的后代(子节点、子节点等)的所有节点。假设 2 .我的预期结果是:3、4、5、6、8。

我知道我可以设计这样的查询:
SELECT child, sys_connect_by_path(child,'/')
FROM T
START WITH parent = 2
CONNECT BY NOCYCLE PRIOR child = PARENT;

这种查询的问题在于它会遍历所有可能的路径,直到它们循环为止,而且在我的实际数据中它们太多了。结果由许多重复项组成 - 这是:
child | sys_connect_by_path (for information)
3 | /3
4 | /3/4
5 | /3/4/5
8 | /3/4/5/8
6 | /3/4/5/8/6
6 | /3/6
5 | /3/6/5
8 | /3/6/5/8
4 | /4
5 | /4/5
8 | /4/5/8
6 | /4/5/8/6
8 | /8
6 | /8/6
5 | /8/6/5

我的实际数据要复杂得多。执行此类查询的成本如此之大,以至于我的可自动扩展的 TEMP 表空间达到 10Gb(最初为 500 Mb)并且我的数据库实际上因为磁盘已满而崩溃。

我试图设计这样的查询(递归 WITH 子句):
WITH descendants(node) AS
( SELECT 2 node FROM dual
UNION ALL
(
SELECT child
FROM T
INNER JOIN descendants D
ON T.parent = D.node
MINUS SELECT node FROM descendants
)
)
SELECT * FROM descendants

我遇到的问题是:
  • 对于 Oracle 10g,这没有实现(ORA-32033: unsupported column aliasing,一些客户使用 Oracle 9 或 10),
  • 使用 Oracle 11g,我得到 ORA-32041: UNION ALL operation in recursive WITH clause must have only two branches .如果我删除 MINUS 子句,我将得到周期( ORA-32044: cycle detected while executing recursive WITH query )。

  • 您将如何查询我的原始数据以有效地获取这些节点 3、4、5、6、8?也欢迎 PL/SQL 解决方案。

    谢谢你。

    最佳答案

    到达任何子节点的预期最大深度是多少?

    如果它相对较小,您可以循环向下,同时检查您已经访问过的节点,以这样的方式......

    (注意,我不是 Oracle 专家,所以这更接近于混合了一点真实 SQL 的伪代码)

    CREATE TABLE myMap (parent INT, child INT);

    INSERT INTO myTable SELECT NULL, 2 FROM DUAL;

    WHILE (SQL%ROWCOUNT > 0)
    LOOP

    INSERT INTO
    myMap
    SELECT DISTINCT
    dataMap.parent,
    dataMap.child
    FROM
    myMap
    INNER JOIN
    dataMap
    ON myMap.child = dataMap.parent
    WHERE
    NOT EXISTS (SELECT * FROM myMap WHERE parent = dataMap.parent)

    END LOOP;

    根据性能,您可能还需要 depth字段在 myMap ;优化加入以便只加入最近的节点。这意味着两个索引;一个用于 JOIN (depth)一个用于 NOT EXISTS (parent) .

    编辑

    添加了 DISTINCT 关键字,以避免以下情况...
    - 节点 2 映射到 3 和 4
    - 节点 3 和 4 都映射到节点 5
    - 节点 5 的所有子节点现在将被处理两次

    GROUP BY 或许多其他选项可用于满足此需求,而不是 DISTINCT。只是 NOT EXISTS 本身是不够的。

    关于sql - Oracle 对非分层数据的分层查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7644791/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com