我需要一些查询分层数据的帮助。下面是单个简单的表,其中parent_id
引用id
,对于根条目可能为 null。
create table edition (
id NUMBER(20),
parent_id NUMBER(20)
);
对于表中的每条记录,我需要找到具有最大 id 的最深的孩子。如果记录没有子记录,则应返回其自己的 ID。我自己尝试过,但使用 A 和 B 是子查询的START WITH A.id = B.id
失败了,看起来 Oracle 不允许这样的连接。
下面是示例数据:
id parent_id
----------------------
1 NULL
2 1
3 1
4 1
5 4
6 5
7 5
和示例结果
id result
----------------------
1 7
2 2
3 3
4 7
5 7
6 6
7 7
我相信你想试试
create table tq84_edition (
id number primary key,
parent_id number references tq84_edition
);
insert into tq84_edition values ( 1, null);
insert into tq84_edition values ( 2, 1);
insert into tq84_edition values ( 3, 1);
insert into tq84_edition values ( 4, 1);
insert into tq84_edition values ( 5, 4);
insert into tq84_edition values ( 6, 5);
insert into tq84_edition values ( 7, 5);
with x (root, id, parent_id, lvl) as (
select id root,
id,
parent_id,
1 lvl
from tq84_edition
UNION ALL
select x.root root,
tq84_edition.id,
tq84_edition.parent_id,
x.lvl + 1 lvl
from x,
tq84_edition
where x.id = tq84_edition.parent_id
)
select root, max(id) keep (dense_rank last order by lvl, id)
from x
group by root;
我能想到的另一种方法,在其他RDBMS上移植更容易:http://www.sqlfiddle.com/#!4/da0a3/19
with parent(root_node, child_of, parent_id, depth) as
(
select id, id, parent_id, 1
from edition
union all
select p.root_node, e.id, e.parent_id, p.depth + 1
from edition e
join parent p on p.child_of = e.parent_id
)
select root_node, max(child_of)
from parent
where (root_node,depth) in
(select root_node,max(depth) from parent group by root_node)
group by root_node
order by root_node
输出:
| ROOT_NODE | MAX(CHILD_OF) |
-----------------------------
| 1 | 7 |
| 2 | 2 |
| 3 | 3 |
| 4 | 7 |
| 5 | 7 |
| 6 | 6 |
| 7 | 7 |
现在,我喜欢甲骨文(也喜欢 http://sqlfiddle.com),它非常简洁。现在我知道 KEEP DENSE_RANK 中 MIN 和 MAX 有什么用了。而之前我没有看到任何关于在 KEEP DENSE_RANK 中显式指定 MIN/MAX 的实用程序。现在我知道它有一个实用性,如果深度上有一些联系,你可以通过使用 MIN 和 MAX 看到谁是第一个和最后一个。
例如 http://www.sqlfiddle.com/#!4/da0a3/24
with parent(root_node, child_of, parent_id, depth) as
(
select id, id, parent_id, 1
from edition
union all
select p.root_node, e.id, e.parent_id, p.depth + 1
from edition e
join parent p on p.child_of = e.parent_id
)
select root_node,
min(child_of) keep(dense_rank last order by depth) as first_in_deepest,
max(child_of) keep(dense_rank last order by depth) as last_in_deepest
from parent
group by root_node;
| ROOT_NODE | FIRST_IN_DEEPEST | LAST_IN_DEEPEST |
--------------------------------------------------
| 1 | 6 | 7 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 6 | 7 |
| 5 | 6 | 7 |
| 6 | 6 | 6 |
| 7 | 7 | 7 |