递归oracle sql来识别一个值

时间:2012-09-04 17:14:18

标签: sql oracle

我有一个表TABA(PK:NAME)以这种方式存储NAME,NAME_TYPE,SOURCE:

NAME  NAME_TYPE SOURCE
----  --------- ------
Name1 Category  S1
Name2 Category  S2
Name3 Datamart  
Name4 Category  S1
Name5 Datamart
Name6 Datamart
Name7 Category  S3

上面的注意:只有当NAME_TYPE = Category时,数据才会出现。

我有另一个表TABA_PARENT,它以这种方式基于name_type存储NAME,PARENT_NAME与NAME列之间的关系。 Datamart与Category的关系是一对多的。

  NAME   PARENT_NAME
    -----  -----------
    Name3  Name1
    Name3  Name2
    Name3  Name4
    Name3  Name5
    Name5  Name1
    Name5  Name6
    Name6  Name7

我的要求是获取TABA的SOURCE,其中NAME_TYPE = Datamart(目前,它在TABA中不存在)

预期产出:

SOURCE column for Name3
-----------------------

S1,S2,S3

诀窍是递归推导出Name3的SOURCE,直到它映射到TABA_PARENT中的类别。

在上面的例子中:

Name3映射到PARENT_NAME Name1,Name2,Name4,Name5。 其中3个(name1,Name2,Name4)属于name_type = Category,因此在TABA中可以使用不同的源 - S1,S2 第四个PARENT_NAME Name5是一个name_type Datamart(源信息不可用),需要进一步扩展,直到达到name_type = Category。

我们拥有Name5映射到PARENT_NAME Name1,Name6的信息。 Name1是一个类别,因此可以推断出来源。 Name6又是Datamart。

但是,Name6最终映射到Name7,这是一个类别,因此源可用 - S3

如上所示,所有映射都必须以递归方式解析,直到达到name_type类别以识别不同的源。

Expected Result: S1,S2,S3 

我正在尝试使用listagg或类似的东西(小的pl / sql代码也可以,但是如果可能的话更喜欢sinlge选择) 我很难递归地做到这一点。 任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

正如评论中所述,这可以通过listagg()的组合来完成,connect by可以从Oracle 11.2开始和a number of other string aggregation techniques available获得。如果你没有使用11.2那么就有SQL Fiddle

select listagg(source, ',' ) within group ( order by source )
  from ( select distinct source
           from taba a
           join ( select parent_name
                    from taba_parent
                   start with name = 'Name3'
                 connect by prior parent_name = name
                         ) b
             on a.name = b.parent_name
                )

distinct子查询仅在那里,因为您有多个相同的源。这将返回S1,S2,S3

为了获得不同名称的相同名称,您可以更改START WITH子句;例如,将其更改为start with name = 'Name5'会返回S1,S3

数据集市没有源这一事实并不重要,因为您只在taba_parent表上使用分层查询,只有在您拥有信息时才加入taba表需要。

这里有一点{{3}}来演示。

答案 1 :(得分:1)

感谢有人试图这样做。 我尝试使用“connect by”和listagg的组合,并获得了预期的结果。

select listagg(source,',') within group (order by source) final_source from ( 
select
distinct
b.source source--,
from taba_parent a, taba b
where b.name = a.parent_name
and b.name_type = 'Category'
connect by prior a.parent_name = a.name
start with a.name = 'Name3'        
);

答案 2 :(得分:0)

您需要一个分层查询(连接)才能获得“终极父级”,然后您需要使用listagg将这些项连接在一起。我只有Oracle 10g,所以我没有listagg。这是分层位:

select distinct source from
(
select taba_parent.name, taba_parent.parent_name, taba.source
from
taba_parent
inner join taba on taba_parent.parent_name = taba.name
)
where name in (select name from taba where name_type = 'Datamart')
connect by name = parent_name
start with source is not null

这给出了:

SOURCE
S3
S2
S1

你可以使用listagg来获得S3,S2,S1