【问题标题】:Need an Oracle hierarchical query that returns only full trees for records where children match a search string需要一个 Oracle 分层查询,该查询仅返回子项与搜索字符串匹配的记录的完整树
【发布时间】:2011-12-06 23:55:24
【问题描述】:

这是该查询的完整示例数据集,没有任何节点与搜索字符串匹配的树进行任何修剪:

级别父 ID 文本 --------------------------------------------- 0 0 1 顶层 1 1 2 富 1 1 3 其他 1 1 4 英尺 0 0 7 顶层2 1 7 8 秒级 1 7 9 另一个二级

如果用户在 'foo' 上搜索,我需要返回以下内容:

0 0 1 顶层 1 1 2 富 1 1 4 英尺

实际情况稍微复杂一些(即我想要返回的树中的三个级别),但这抓住了问题所在。在英文中,返回与搜索字符串匹配的节点的祖先树,从文本列上的匹配节点开始,并返回所有祖先。

我是 Oracle 的新手(至少最近是这样)并尝试添加到 CONNECT BY 子句但没有成功 - 总是返回以下内容:

1 1 2 富 1 1 4 英尺

PS - 相关的 oracle 文档和示例暗示 CONNECT_BY_ROOT 将捕获祖先,但它似乎所做的只是返回顶级 (ROOT) 值。

【问题讨论】:

标签: oracle hierarchical-trees hierarchical-query


【解决方案1】:

取决于您对 LEVEL 列的使用(根据我的评论)。

有关 Oracle 分层查询的信息:http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/queries003.htm

如果 LEVEL 是 Oracle 伪列,这将返回您要求的内容:

WITH t AS (SELECT 0 AS parent,
                  1 AS id,
                  'toplevel' AS text FROM DUAL
           UNION
           SELECT 1 AS parent,
                  2 AS id,
                  'foo' AS text FROM DUAL
           UNION
           SELECT 1 AS parent,
                  3 AS id,
                  'sumthin else' AS text FROM DUAL
           UNION
           SELECT 1 AS parent,
                  4 AS id,
                  'foo' AS text FROM DUAL
           UNION
           SELECT 0 AS parent,
                  7 AS id,
                  'toplevel2' AS text FROM DUAL
           UNION
           SELECT 7 AS parent,
                  8 AS id,
                  'secondlevel' AS text FROM DUAL
           UNION
           SELECT 7 AS parent,
                  9 AS id,
                  'anothersecondlevel' AS text FROM DUAL
          ) 
SELECT UNIQUE
       level,
       parent,
       id,
       text
  FROM t
 START WITH text = 'foo'
 CONNECT BY PRIOR parent = id
 ORDER BY parent;

返回:

LEVEL PARENT ID TEXT
    2      0  1 toplevel
    1      1  2 foo     
    1      1  4 foo     

如果 LEVEL 是表中的一列,则:

WITH t AS (SELECT 0 AS tlevel,
                  0 AS parent,
                  1 AS id,
                  'toplevel' AS text FROM DUAL
           UNION
           SELECT 1 AS tlevel,
                  1 AS parent,
                  2 AS id,
                  'foo' AS text FROM DUAL
           UNION
           SELECT 1 AS tlevel,
                  1 AS parent,
                  3 AS id,
                  'sumthin else' AS text FROM DUAL
           UNION
           SELECT 1 AS tlevel,
                  1 AS parent,
                  4 AS id,
                  'foo' AS text FROM DUAL
           UNION
           SELECT 0 AS tlevel,
                  0 AS parent,
                  7 AS id,
                  'toplevel2' AS text FROM DUAL
           UNION
           SELECT 1 AS tlevel,
                  7 AS parent,
                  8 AS id,
                  'secondlevel' AS text FROM DUAL
           UNION
           SELECT 1 AS tlevel,
                  7 AS parent,
                  9 AS id,
                  'anothersecondlevel' AS text FROM DUAL
          ) 
SELECT UNIQUE
       tlevel,
       parent,
       id,
       text
  FROM t
 START WITH text = 'foo'
 CONNECT BY PRIOR parent = id
 ORDER BY parent;

返回:

TLEVEL PARENT ID TEXT
     0      0  1 toplevel
     1      1  2 foo     
     1      1  4 foo     

希望对你有帮助...

【讨论】:

    【解决方案2】:

    要从下往上遍历,重要的位是CONNECT BY PRIOR之后的值的顺序) order by 用于反转输出(因为根是 foo),distinct 删除重复的顶级值:

    SELECT DISTINCT LEVEL, id, text
    FROM t1
    CONNECT BY PRIOR parent = id
    START WITH text = 'foo'
    ORDER BY LEVEL DESC
    

    注意:如果你添加一个孩子到 foo 并切换 CONNCT BY PRIOR id = parent 你会得到孩子

    如果您想查看整个层次结构,您可以找到树的顶部 (通过寻找没有父级的行)

    SELECT id
    FROM t1
    WHERE parent=0
    CONNECT BY PRIOR parent = id
    START WITH text = 'foo'
    

    然后将其用作 START WITH id(并反转外部查询中树遍历的顺序,id = parent):

    SELECT DISTINCT LEVEL, id, text
    FROM t1
    CONNECT BY PRIOR id = parent
    START WITH id IN 
    (
        SELECT id
        FROM t1
        WHERE parent=0
        CONNECT BY PRIOR parent = id
        START WITH text = 'foo'
    )
    ORDER BY LEVEL DESC
    

    【讨论】:

    • 反转 CONNECT BY 的意义给了我正确的结果集。仍在努力正确排序,因为从底部遍历树的更改似乎覆盖了任何对输出进行排序的尝试,使得树仍然保持在一个连续的集合中。
    • 不知道为什么排序不起作用,也许你需要从上到下走?
    • 骗子的分类和消除现已全部设置完毕。感谢大家的协助!
    【解决方案3】:

    我对“仅返回完整树的 Oracle 分层查询”部分的看法是:

    SELECT Parent_ID    
         , Child_ID 
         , INITIAL_Parent_ID
         , child_level
         , INITIAL_Parent_ID || children_CHAIN AS CONNECTION_CHAIN
    FROM ( SELECT CONNECT_BY_ROOT Parent_ID AS INITIAL_Parent_ID
                , Parent_ID
                , Child_ID
                , LEVEL AS child_level
                , SYS_CONNECT_BY_PATH(Child_ID, '/') AS children_chain
           FROM REF_DECOMMISSIONS
           CONNECT BY NOCYCLE Parent_ID = PRIOR Child_ID
         )
    WHERE INITIAL_Parent_ID NOT IN (SELECT Child_ID FROM REF_DECOMMISSIONS)
    ;
    

    要将树过滤为包含特定子项的树,您需要在最后一个 WHERE 中添加另一个条件以进一步过滤 INITIAL_Parent_ID。 查询将变为:

    WITH ROOT_TREES AS
    ( SELECT Parent_ID  
           , Child_ID   
           , INITIAL_Parent_ID
           , child_level
           , INITIAL_Parent_ID || children_CHAIN AS CONNECTION_CHAIN
      FROM ( SELECT CONNECT_BY_ROOT Parent_ID AS INITIAL_Parent_ID
                  , Parent_ID
                  , Child_ID
                  , LEVEL AS child_level
                  , SYS_CONNECT_BY_PATH(Child_ID, '/') AS children_chain
             FROM REF_DECOMMISSIONS
             CONNECT BY NOCYCLE Parent_ID = PRIOR Child_ID
           )
      WHERE INITIAL_Parent_ID NOT IN (SELECT Child_ID FROM REF_DECOMMISSIONS)
    )
    SELECT * 
      FROM root_trees 
    WHERE INITIAL_Parent_ID IN (SELECT INITIAL_Parent_ID 
                                  FROM root_trees 
                                 WHERE Child_ID = 123)
    ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-03
      相关资源
      最近更新 更多