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 分层查询的主要内容,如果未能解决你的问题,请参考以下文章

具有多个父级的 Oracle 分层查询

Oracle 分层查询

oracle ebs r12报告的Oracle flex值层次结构SQL查询

如何使用分层子查询构建层次结构路径

有没办法在postgreSQL中查询oracle上的数据

使用索引进行 Oracle Sql 调优