Oracle "connect by prior" 和 "max() over partition by" 一起删除重复的子树
Oracle "connect by prior" along with "max() over partition by" to remove duplicate subtree
我正在尝试删除由 "connect by prior" 子句编辑的重复子树 return。我想检查树层次结构的顶级节点,用户可以在其中输入已经是子树一部分的子 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);
此查询 return 的结果为:
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
我希望 return 仅那些级别为 max_level 的顶级节点。 IE。我的查询应该 return 结果为:
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"
如果您对如何操作有任何想法,请告诉我。
谢谢,
在另一个 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
你的逻辑有效,但有点蛮力方法,即检查所有可能性,select仅有效。
一种替代方法很简单,可以限制您的 START WITH
仅考虑 离开 节点。
这可以通过排除所有 parent 节点的节点来完成:
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
我正在尝试删除由 "connect by prior" 子句编辑的重复子树 return。我想检查树层次结构的顶级节点,用户可以在其中输入已经是子树一部分的子 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);
此查询 return 的结果为:
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
我希望 return 仅那些级别为 max_level 的顶级节点。 IE。我的查询应该 return 结果为:
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"
如果您对如何操作有任何想法,请告诉我。 谢谢,
在另一个 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
你的逻辑有效,但有点蛮力方法,即检查所有可能性,select仅有效。
一种替代方法很简单,可以限制您的 START WITH
仅考虑 离开 节点。
这可以通过排除所有 parent 节点的节点来完成:
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