Reputation: 190
Good Folks,
let's assume a tree like this:
A (100) | +--B (50) | | | C (NULL) | | | E (NULL) | +--D (30) | B (20)
In this tree a letter shall represent a node's name and the number in parentheses some value. I know how to crawl through all nodes with a hierarchical query (using connect by etc.). However, I would like to retrieve the non-null value of the (grand-)parent node, if the current node's value is null. Thus, such a query should yield a table like the following:
NAME PARENT VALUE A NULL 100 B A 50 B D 20 C B 50 D A 30 E C 50
Does anyone of you know how to achieve this?
Code so far:
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
EDIT:
Instead of a table with parent references, you might as well consider a table with child references like this:
NAME CHILD VALUE A B 100 A D 100 B C 50 C E NULL E NULL NULL D B 30 B NULL 20
which should translate to:
NAME CHILD VALUE A B 100 A D 100 B C 50 C E 50 E NULL 50 D B 30 B NULL 20
Upvotes: 1
Views: 71
Reputation: 9091
I'd recommend Ponder's CTE answer. If you must use CONNECT BY for some reason, Oracle doesn't offer many ways to access prior rows in the hierarchy - there's either PRIOR (which only goes 1 level back), or CONNECT_BY_ROOT (which only looks at the root node), or SYS_CONNECT_BY_PATH (which is cumbersome to use, since you need to resort to string manipulation).
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;
Upvotes: 1
Reputation: 14858
Problem with your data is that B
has two parent nodes and also has child node, so this part of tree is replicated. Anyway you can achieve your goal easily with recursive 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
Upvotes: 3