好伙计们,
让我们假设有这样的树:
A (100( | +--B (50( | | | C(空( | | | E(空( | +--D (30( | B (20(
在此树中,字母应表示节点的名称,括号中的数字应表示某个值。 我知道如何通过分层查询(使用连接方式等(爬取所有节点。 但是,如果当前节点的值为空,我想检索(主(父节点的非空值。 因此,此类查询应生成如下所示的表:
命名父值 空 100 乙 A 50 乙 D 20 C B 50 D A 30 E C 50
你们中有人知道如何做到这一点吗?
到目前为止的代码:
SELECT NAME, PARENT,
CASE VALUE
WHEN IS NULL THEN (SELECT VALUE FROM SOMETABLE WHERE NAME = PARENT) -- this returns more than one value
ELSE VALUE
END CASE AS VALUE
FROM SOMETABLE
START WITH NAME='A'
CONNECT BY NOCYCLE PRIOR NAME = PARENT
编辑:
与其使用带有父引用的表,不如考虑一个包含子引用的表,如下所示:
命名子值 阿 B 100 A D 100 乙 C 50 C E 空 E 空空 D B 30 B 空 20
,应转换为:
命名子值 阿 B 100 A D 100 乙 C 50 C E 50 E 空 50 D B 30 B 空 20
数据的问题在于B
有两个父节点,并且还具有子节点,因此复制树的这一部分。无论如何,您可以使用递归 CTE 轻松实现您的目标:
with c(name, parent, value) as (
select name, parent, value from sometable where name = 'A' union all
select t.name, t.parent, nvl(t.value, c.value)
from c join sometable t on c.name = t.parent)
select * from c
DBfiddle 演示
我推荐Ponder的CTE答案。如果出于某种原因必须使用 CONNECT BY,Oracle 没有提供很多方法来访问层次结构中的前几行 - 要么是 PRIOR(它只后退 1 级(,要么是 CONNECT_BY_ROOT(它只查看根节点(,要么是SYS_CONNECT_BY_PATH(使用起来很麻烦,因为您需要诉诸字符串操作(。
SELECT NAME, PARENT,
-- COALESCE(VALUE, PRIOR VALUE) AS VALUE, -- only works 1 level back
regexp_substr(rtrim(SYS_CONNECT_BY_PATH(value, ','),','),'[^,]*$') as VALUE
FROM SOMETABLE
START WITH NAME='A'
CONNECT BY NOCYCLE PRIOR NAME = PARENT;