Oracle 中的递归查询,直到层次结构中的父级满足条件?
Recursive query in Oracle until a parent in the hierarchy meets a condition?
我有一个 table 如下所示:
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
而且我希望能够获取每个 ID 及其对应的 VALUE_ID。我想这样做的方式是,如果一行的 VALUE_ID 为 NULL,它会“继承”层次结构中位于其上方的第一个父级的 VALUE_ID,该父级具有 VALUE_ID 作为 NOT NULL。这就是查询结果:
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
仅用一个递归或分层查询就可以完成这样的事情吗?还是可以在没有程序的情况下完成,也许?使用 CTE 或 CONNECT BY 子句?
您可以为此使用递归 CTE:
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 是一个 db<>fiddle.
您可以使用相关的分层查询和 CONNECT_BY_ISLEAF
仅 return 一行:
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
因此,对于您的测试数据:
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
这输出:
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
我有一个 table 如下所示:
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
而且我希望能够获取每个 ID 及其对应的 VALUE_ID。我想这样做的方式是,如果一行的 VALUE_ID 为 NULL,它会“继承”层次结构中位于其上方的第一个父级的 VALUE_ID,该父级具有 VALUE_ID 作为 NOT NULL。这就是查询结果:
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
仅用一个递归或分层查询就可以完成这样的事情吗?还是可以在没有程序的情况下完成,也许?使用 CTE 或 CONNECT BY 子句?
您可以为此使用递归 CTE:
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 是一个 db<>fiddle.
您可以使用相关的分层查询和 CONNECT_BY_ISLEAF
仅 return 一行:
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
因此,对于您的测试数据:
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
这输出:
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