1

我正在尝试删除由“先连接”子句返回的重复子树。我希望检查树层次结构的顶级节点,用户可以在其中输入已经是子树一部分的子 ID。看看下面的例子:

SELECT * FROM (
With test_hierarchy as(
       SELECT 'a' parent, 'b' child FROM dual UNION ALL
       SELECT 'b','c' FROM dual UNION ALL
       SELECT 'd','e' FROM dual UNION ALL
       SELECT 'e','f' FROM dual UNION ALL
       SELECT 'f','g' FROM dual UNION ALL
       SELECT 'f','h' FROM dual)
SELECT
    parent,
    child,
    CONNECT_BY_ROOT child AS init_child,
    LEVEL,
    CONNECT_BY_ISLEAF,
    MAX(LEVEL) OVER(
        PARTITION BY parent
    ) AS max_level
FROM
    test_hierarchy
WHERE
    CONNECT_BY_ISLEAF = 1
START WITH
    child IN (
        'c', 'b', 'e', 'f', 'h', 'g'
    )
CONNECT BY
    PRIOR parent = child);

此查询返回结果为:

P C I      LEVEL CONNECT_BY_ISLEAF  MAX_LEVEL
- - - ---------- ----------------- ----------
a b b          1                 1          2
a b c          2                 1          2
d e g          3                 1          3
d e f          2                 1          3
d e h          3                 1          3
d e e          1                 1          3

我希望只返回那些 level = max_level 的顶级节点。即我的查询应返回结果为:

P C I      LEVEL CONNECT_BY_ISLEAF  MAX_LEVEL
- - - ---------- ----------------- ----------
a b c          2                 1          2
d e g          3                 1          3
d e h          3                 1          3

如果我尝试使用 WHERE 子句作为“WHERE level = max_level”过滤掉结果,Oracle 会抱怨:

ORA-01788: CONNECT BY clause required in this query block
01788. 00000 -  "CONNECT BY clause required in this query block"

如果您对如何操作有任何想法,请告诉我。谢谢,

4

2 回答 2

1

您的逻辑可以工作,但是是一种蛮力方法,即检查所有可能性并仅选择有效的。

一种替代方法是简单地限制您仅START WITH考虑离开节点。

这可以通过排除所有作为 节点的节点来完成:

START WITH
    child IN ( 'c', 'b', 'e', 'f', 'h', 'g') and
    child not in (select parent from test_hierarchy)

由于START列表有限,最终查询具有更好的性能,并且您无需WINDOWS SORT即可获得最大级别:

With test_hierarchy as(
       SELECT 'a' parent, 'b' child FROM dual UNION ALL
       SELECT 'b','c' FROM dual UNION ALL
       SELECT 'd','e' FROM dual UNION ALL
       SELECT 'e','f' FROM dual UNION ALL
       SELECT 'f','g' FROM dual UNION ALL
       SELECT 'f','h' FROM dual)
SELECT
    parent,
    child,
    CONNECT_BY_ROOT child AS init_child,
    LEVEL,
    CONNECT_BY_ISLEAF
FROM
    test_hierarchy
WHERE
    CONNECT_BY_ISLEAF = 1 
START WITH
    child IN ( 'c', 'b', 'e', 'f', 'h', 'g') and
    child not in (select parent from test_hierarchy)
CONNECT BY
    PRIOR parent = child;

P C I      LEVEL CONNECT_BY_ISLEAF
- - - ---------- -----------------
a b c          2                 1
d e g          3                 1
d e h          3                 1
于 2019-01-31T16:48:43.550 回答
1

将您的递归查询包装在另一个 CTE 中并对其进行过滤:

WITH 
  test_hierarchy AS (
    SELECT 'a' parent, 'b' child FROM dual UNION ALL
    SELECT 'b','c' FROM dual UNION ALL
    SELECT 'd','e' FROM dual UNION ALL
    SELECT 'e','f' FROM dual UNION ALL
    SELECT 'f','g' FROM dual UNION ALL
    SELECT 'f','h' FROM dual
  ),
  recursion AS (
    SELECT
      parent,
      child,
      CONNECT_BY_ROOT child AS init_child,
      LEVEL AS lvl,
      CONNECT_BY_ISLEAF AS isleaf,
      MAX(LEVEL) OVER(
        PARTITION BY parent
      ) AS max_level
    FROM
      test_hierarchy
    START WITH child IN ('c', 'b', 'e', 'f', 'h', 'g')
    CONNECT BY PRIOR parent = child
  )
SELECT *
FROM recursion
WHERE isleaf = 1 AND lvl = max_level
于 2019-01-31T14:37:04.993 回答