分层 SQL/PL 查询中 parents 的最新值
Latest values of parents in hierarchical SQL/PL query
好人,
让我们假设一棵这样的树:
A (100)
|
+--B (50)
| |
| C (NULL)
| |
| E (NULL)
|
+--D (30)
|
B (20)
在这棵树中,一个字母应该代表一个节点的名称,parent中的数字是一些值。
我知道如何使用分层查询(使用 connect by 等)遍历所有节点。
但是,如果当前节点的值为空,我想检索 (grand-)parent 节点的 non-null 值。
因此,这样的查询应该产生如下所示的 table:
NAME PARENT VALUE
A NULL 100
B A 50
B 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
编辑:
与其使用 parent 引用的 table,不如考虑使用 child 引用的 table,如下所示:
NAME CHILD VALUE
A B 100
A D 100
B C 50
C E NULL
E NULL NULL
D B 30
B NULL 20
应该翻译成:
NAME CHILD VALUE
A B 100
A D 100
B C 50
C E 50
E NULL 50
D B 30
B NULL 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
我推荐 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;
好人,
让我们假设一棵这样的树:
A (100) | +--B (50) | | | C (NULL) | | | E (NULL) | +--D (30) | B (20)
在这棵树中,一个字母应该代表一个节点的名称,parent中的数字是一些值。 我知道如何使用分层查询(使用 connect by 等)遍历所有节点。 但是,如果当前节点的值为空,我想检索 (grand-)parent 节点的 non-null 值。 因此,这样的查询应该产生如下所示的 table:
NAME PARENT VALUE A NULL 100 B A 50 B 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
编辑:
与其使用 parent 引用的 table,不如考虑使用 child 引用的 table,如下所示:
NAME CHILD VALUE A B 100 A D 100 B C 50 C E NULL E NULL NULL D B 30 B NULL 20
应该翻译成:
NAME CHILD VALUE A B 100 A D 100 B C 50 C E 50 E NULL 50 D B 30 B NULL 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
我推荐 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;