Reputation: 15
I have a table like the following:
ID PARENT_ID VALUE_ID
1 NULL 100
2 1 NULL
3 2 200
4 3 NULL
5 1 300
6 2 NULL
7 6 400
8 7 500
And I'd like to be able to fetch each ID with its corresponding VALUE_ID. I want to do it in such a way that if a row has a VALUE_ID as NULL, it "inherits" the VALUE_ID of the first parent above it in the hierarchy, that has a VALUE_ID as NOT NULL. So that would be the query result:
ID VALUE_ID
1 100
2 100 // -> inherits the value from PARENT_ID = 1;
3 200
4 200 // -> inherits the value from PARENT_ID = 3;
5 300
6 100 // -> inherits the value from ID = 1, because the PARENT_ID = 2 also has VALUE_ID as NULL, so it goes deeper in the hierarchy;
7 400
8 500
Could such a thing be accomplished with only one recursive or hierarchical query? Or be accomplished in general without a procedure, perhaps? With CTE, or CONNECT BY clause?
Upvotes: 1
Views: 4124
Reputation: 167982
You can use a correlated hierarchical query and CONNECT_BY_ISLEAF
to only return a single row:
SELECT id,
parent_id,
( SELECT value_id
FROM table_name r
WHERE connect_by_isleaf = 1
START WITH r.id = t.id
CONNECT BY PRIOR parent_id = id
AND PRIOR value_id IS NULL
) AS value_id
FROM table_name t
So, for your test data:
CREATE TABLE table_name ( ID, PARENT_ID, VALUE_ID ) AS
SELECT 1, NULL, 100 FROM DUAL UNION ALL
SELECT 2, 1, NULL FROM DUAL UNION ALL
SELECT 3, 2, 200 FROM DUAL UNION ALL
SELECT 4, 3, NULL FROM DUAL UNION ALL
SELECT 5, 1, 300 FROM DUAL UNION ALL
SELECT 6, 2, NULL FROM DUAL UNION ALL
SELECT 7, 6, 400 FROM DUAL UNION ALL
SELECT 8, 7, 500 FROM DUAL
This outputs:
ID | PARENT_ID | VALUE_ID -: | --------: | -------: 1 | null | 100 2 | 1 | 100 3 | 2 | 200 4 | 3 | 200 5 | 1 | 300 6 | 2 | 100 7 | 6 | 400 8 | 7 | 500
db<>fiddle here
Upvotes: 2
Reputation: 1269773
You can use a recursive CTE for this:
with cte(id, value_id, parent_value_id) as (
select id, value_id, value_id as parent_value_id
from t
where value_id is not null
union all
select t.id, t.value_id, cte.parent_value_id
from cte join
t
on t.parent_id = cte.id
where t.value_id is null
)
select *
from cte
order by id;
Here is a db<>fiddle.
Upvotes: 2