Oracle 分层查询
Posted
技术标签:
【中文标题】Oracle 分层查询【英文标题】:Oracle Hierarchical Queries 【发布时间】:2016-05-21 14:41:11 【问题描述】:我正在努力处理具有以下要求的查询:
表 A
ID名称键 1 A1 键1 2 A2 键 2 3 A3 键3表 B
ID A_ID 名称 CONTAINER_A_ID 1 1 B1 空 2 1 B2 空 3 1 B3 2 4 2 B4 空 5 2 B5 空 6 3 B6 空 7 3 B7 空表 A 中的 Key 列是唯一的
表B中的A_ID列是表A的外键
表 B 中的 CONTAINER_A_ID 列表示表 B 中的行可以是 容器,它包含由 CONTAINER_A_ID 值指示的其他数据行。
下面是例子:
输入参数为表A键列值,假设A.Key = 'key1',根据上述样本数据得出的结果为:
A.ID A.NAME A.KEY B.ID B.A_ID B.NAME B.CONTAINER_A_ID 1 A1 KEY1 1 1 B1 空 1 A1 KEY1 2 1 B2 空 1 A1 键 1 3 1 B3 2 2 A2 KEY2 4 2 B4 空 2 A2 KEY2 5 2 B5 空如果输入参数是A.Key = 'key2',那么结果是:
A.ID A.NAME A.KEY B.ID B.A_ID B.NAME B.CONTAINER_A_ID 2 A2 KEY2 4 2 B4 空 2 A2 KEY2 5 2 B5 空谢谢
【问题讨论】:
如果您添加A.Key = 'key1'
作为条件,则将永远不会返回最后两个注册表!那是你真正需要的吗?
是的,是的。我将在我的帖子中提供更多示例以使我的问题更清楚,谢谢。
我想我刚刚明白了。过滤器中的注册表和过滤结果中的子项。我想这会有点难。我不会尝试提供答案,因为我这里没有预言机来测试它。使用 CTE 的东西也许应该解决它。
【参考方案1】:
这是在 Oracle 11g 上。
如果您专门寻找 CONNECT BY 我还不知道。
drop table t1; drop table t2;
create table t1 (id int primary key, name char(5), key char(5));
create table t2 (id int primary key, a_id int, name char(5) , container int);
insert into t1 values (1, 'A1', 'K1');
insert into t1 values (2, 'A2', 'K2');
insert into t1 values (3, 'A3', 'K3');
insert into t2 values (1, 1, 'B1', null);
insert into t2 values (2, 1, 'B2', null);
insert into t2 values (3, 1, 'B3', 2);
insert into t2 values (4, 2, 'B4', null);
insert into t2 values (5, 2, 'B5', null);
insert into t2 values (6, 3, 'B6', null);
insert into t2 values (7, 3, 'B7', null);
with t(id, name, key, bid, aid, bname, con) as (
select a.id, a.name, a.key, b.id, b.a_id, b.name, b.container
from t1 a
inner join
t2 b
on a.id = b.a_id
where a.key = 'K1'
union all
select a.id, a.name, a.key, b.id, b.a_id, b.name, b.container
from t t
inner join
t1 a
on a.id = t.con
inner join
t2 b
on a.id = b.a_id
) select * from t;
编辑:回应豪尔赫的评论
insert into t2 values (4, 2, 'B4', 3);
【讨论】:
那会从小孩子解决孩子吗?我的意思是如果insert into t2 values (4, 2, 'B4', 3);
怎么办?您的查询是否有效?
@Jorge 我相信确实如此 - 见上文。如果您发现任何问题,请告诉我。
太棒了。为你 +1 :)【参考方案2】:
这是给Hierarchical Query
with TableA as
(
select 1 id, 'A1' Name, 'Key1' key from dual union all
select 2, 'A2', 'Key2' from dual union all
select 3, 'A3', 'Key3' from dual
)
, tableb as
(
select 1 id, 1 a_id, 'B1' name , null CONTAINER_A_ID from dual union all
select 2 , 1 , 'B2' , null from dual union all
select 3 , 1 , 'B3' , 2 from dual union all
select 4 , 2 , 'B4' , null from dual union all
select 5 , 2 , 'B5' , null from dual union all
select 6 , 3 , 'B6' , null from dual union all
select 7 , 3 , 'B7' , null from dual
)
select
a.id, a.name, a.key, b.id, b.a_id, b.name, b.container_a_id
from
tableb b
left join
tablea a
on
a.id = b.a_id
start with
A.Key = 'Key1'
connect by
prior b.container_a_id = b.a_id;
如果您需要订购,请在末尾添加order by a.id, b.id,a.name,...;
。
【讨论】:
【参考方案3】:CTE 可以在 11g Oracle 中使用。我刚刚看到豪尔赫在我面前。如果您只是在 CTE 中使用 tableB 然后加入 CTE 以获取所有字段,则更容易看到递归是如何工作的,像这样
with
recurse (a_id, b_id, parent_id)
as
(select a_id, id, container_a_id as parent_id
from tableB
WHERE A_ID = 1 -- Put your parameter here
union all
select b.a_id, b.id, b.container_a_id
from recurse r, tableB b
where b.a_id = r.parent_id
)
select r.a_id, a.name, a.key, b.id, b.a_id, b.name, b.container_a_id
from recurse r, tableA a, tableB b
where r.a_id = a.id and r.b_id = b.id
;
这得到了相同的结果,但是虽然您必须使用 a_id 而不是 a_key 作为条件,但理解递归要容易一些。
所以,把这个留在这里,以防它帮助人们了解一些关于 CTE 的知识。
【讨论】:
以上是关于Oracle 分层查询的主要内容,如果未能解决你的问题,请参考以下文章