【问题标题】:recursive oracle sql to identify a value递归oracle sql来识别一个值
【发布时间】:2012-08-29 09:35:11
【问题描述】:

我有一个表 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,PARENT_NAME 以及基于 name_type 的 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(source info not available),需要进一步扩展,直到达到name_type = Category。

我们知道 Name5 映射到 PARENT_NAME Name1,Name6。 Name1 是一个类别,因此可以推断出来源。 Name6 又是一个数据集市。

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

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

Expected Result: S1,S2,S3 

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

【问题讨论】:

  • 我无法回答自己的问题。因此,我在评论部分回答。
  • 感谢任何尝试此操作的人。我尝试使用“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'通过先前的 a.parent_name = a.name 连接 a.name = 'Name3' );
  • 如果您不打算接受其他小伙子的答案之一,请将其发布为答案。
  • 我试过了,但是网站不允许我在 48 小时内接受我自己的答案。之后我会接受我自己的答案。

标签: sql oracle


【解决方案1】:

正如 cmets 中所述,这可以通过结合使用 listagg()(从 Oracle 11.2 开始提供)和 connect by 来完成。如果您不使用 11.2,则有 a number of other string aggregation techniques available

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 表。

这里有一个小SQL Fiddle 来演示。

【讨论】:

  • 谢谢大家。我看到提供的解决方案与我想出的相同,所有这些工作。
【解决方案2】:

感谢任何尝试此操作的人。 我尝试使用“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'        
);

【讨论】:

    【解决方案3】:

    您需要一个分层查询(连接方式)来获取您的“最终父级”,然后您需要使用 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

    【讨论】:

    • 谢谢大家。我看到提供的解决方案与我在您的回复和所有这些工作之前提出的解决方案相同。
    猜你喜欢
    • 2021-12-25
    • 2018-06-20
    • 2013-07-09
    • 2020-11-27
    • 1970-01-01
    • 2012-10-07
    • 1970-01-01
    • 2021-12-26
    • 2014-09-14
    相关资源
    最近更新 更多