【问题标题】:SQL Multi Condition CTE RecursionSQL 多条件 CTE 递归
【发布时间】:2011-10-20 18:03:01
【问题描述】:

在数据库中,每个标识符都有以下 2 条信息。控制他们的公司,以及他们有少量控制权的公司。

类似的东西,2 个表(忽略一些唯一标识符):

组织

orgid | org_immediate_parent_orgid
1     | 2
2     | 2
3     | 1
5     | 4

关系 orgid --> org_immediate_parent_orgid 表示公司有父级。告诉我它的唯一相关 org_immediate_parent_orgid --> 公司的母公司作为子公司的 orgid

org_affiliations

orgid | affiliated_orgid
2     | 3
2     | 5
4     | 1
1     | 5

orgid --> associated_orgid 是公司有附属公司

视觉表示应该是这样的:

关于组织的红色关系,关于蓝色关系org_affiliations

如果想要让 2(或 2 的子公司)拥有的所有公司都参与其中:

select m.org_immediate_parent_orgid
,m.orgid
from oa.organizations m
where m.org_immediate_parent_orgid is not null
start with m.orgid in (Identifiers)
connect by nocycle prior  m.orgid=m.org_immediate_parent_orgid

返回

org_immediate_parent_orgid| orgid
1                         | 2
2                         | 2
3                         | 1

如果想要让所有公司都 2(或 2 的附属儿子)参与其中:

select aff.orgid,aff.affiliated_orgid
from oa.org_affiliations aff
where aff.affiliated_orgid is not null
start with aff.orgid in(Identifiers)
connect by nocycle prior  aff.affiliated_orgid =aff.orgid

返回

orgid | affiliated_orgid
2     | 3
2     | 5

所有可能的关系:

  • Aff --> Aff
  • Aff --> 子
  • 子 --> Aff
  • 子 --> 子

我只找到Sub --> Sub(子公司的子公司),relationship (2 --> 1 andrelationship 1 --> 3) and Aff --> Aff,relationship (2 --> 3 andrelationship 2 - -> 5)。它还需要我 2 个单独的查询。

如何在一个递归查询中提取所有可能的关系?

如果我通过标识符 2,则应该有可能返回以下内容:

Relation | Loop| orgid | children
Sub      | 1   | 2     |2
Sub      | 1   | 2     |1
Aff      | 1   | 2     |3
Aff      | 1   | 2     |5
Sub      | 2   | 1     |3
Aff      | 2   | 1     |5

在每个周期中都会检查每个标识符的子和附属。对新的孩子重复。

知道如何处理它吗?

TL:DR: 2 个表(子公司\附属公司),2 个查询。想要一个查询,我从一家公司那里找到所有子公司和附属公司以及所有可能的 subs\affs 组合。最终预期结果展示,按照图片表示即可。

编辑:正如 Craig 所说,我修复了输出。

Edit2:在 Craig 和 Bob Jarvis 给予的良好帮助之后,我继续遇到问题。

对于收集子公司,以下代码完美无缺,输出如我所愿:

with
relations as
(
select orgid as children,org_immediate_parent_orgid as orgid,'Sub' as relation
from oa.organizations 
)
select distinct relation, level, orgid, children
from relations
where children is not null
start with orgid in (identifier)
connect by
nocycle prior children = orgid
order by 2,3,4

AFF 也一样:

with
relations as
(
select affiliated_orgid as children, orgid as orgid,'Aff' as relation
from oa.org_affiliations    
)
select distinct relation, level, orgid, children
from relations
where children is not null
start with orgid in (identifier)
connect by
nocycle prior children = orgid
order by 2,3,4

但不能有“联合所有”?

with
relations as
(
select orgid as children,org_immediate_parent_orgid as orgid,'Sub' as relation
from oa.organizations

UNION ALL

select affiliated_orgid as children, orgid as orgid,'Aff' as relation
from oa.org_affiliations    
)
select distinct relation, level, orgid, children
from relations
where children is not null
start with orgid in (identifier)
connect by
nocycle prior children = orgid
order by 2,3,4

在 sql developer 中,我检查了“解释从 7 到 400k 的每次跳跃的计划和成本,只需添加“union all”。任何解决方法?问题是在 CTE 内部,在 union alL 中吗?

Bob Jarvis 解决方案在我有 comp-sub-sub-aff 的情况下不起作用,或者它找到公司的所有子公司或所有附属公司

【问题讨论】:

  • +1 剪裁美。但是,太长了……没听:)
  • 太长了,我无法阅读、理解和回复!
  • TL:DR: 2 个表(子公司\附属公司),2 个查询。想要一个查询,我从一家公司那里找到所有子公司和附属公司以及所有可能的 subs\affs 组合。最终预期结果展示,按照图片表示即可。
  • @blueomega - 你有没有想过这个问题,或者你还有问题吗?如果还是不行,我再看看。

标签: sql recursion plsql common-table-expression recursive-query


【解决方案1】:

这是一个开始:

select 'SUB -> SUB' AS TYPE,
       m.orgid AS ORGID,
       m.org_immediate_parent_orgid AS PARENT_OR_AFF
  from organizations m
  where m.org_immediate_parent_orgid is not NULL
  start with m.orgid in (2)
  connect by nocycle prior m.orgid = m.org_immediate_parent_orgid
UNION ALL
select 'AFF -> AFF' AS TYPE,
       aff.orgid AS ORGID,
       aff.affiliated_orgid AS PARENT_OR_AFF
  from org_affiliations aff
  where aff.affiliated_orgid is not NULL
  start with aff.orgid IN (2)
  connect by nocycle prior aff.affiliated_orgid = aff.orgid;

如果您添加子查询以获取剩余的关系,您应该可以继续使用。

分享和享受。

【讨论】:

    【解决方案2】:

    将其从评论变为实际答案,并提供我认为您需要的内容。

    有几件事..一个是次要的..我相信你有你的第一个连接的标签,通过返回输出向后。另外,我不明白您如何在最终输出中获得最后两行。 4 是 5 的父母,而不是孩子,那为什么会出现呢?如果它不存在,那么最后一行也不会存在。

    如果我没看错的话,你可以使用类似:

    with
    relations as
    (
        select
            orgid,
            org_immediate_parent_orgid parent_id,
            'Sub' relation
        from
            organizations
        union all
        select
            orgid,
            null parent_id,
            'Aff' relation
        from
            org_affiliations
        where
            orgid not in (
                select affiliated_orgid
                from org_affiliations
            )
        union all
        select
            affiliated_orgid orgid,
            orgid parent_id,
            'Aff' relation
        from
            org_affiliations
    )
    select distinct relation, level, parent_id, orgid
    from relations
    where parent_id is not null
    start with orgid = 2
    connect by
        nocycle prior orgid = parent_id
    order by 2,3,4
    

    它给出以下输出:

    RELATION|LEVEL|PARENT_ID|ORGID
    Sub     |1    |2        |2
    Sub     |2    |2        |1
    Aff     |2    |2        |3
    Aff     |2    |2        |5
    Sub     |3    |1        |3
    Aff     |3    |1        |5
    

    最大的问题是 2 个表彼此相对设置(组织有一个到父级的链接,从属关系有一个到子级的链接)。所以我在 WITH 子句中将它们制作成相同的格式,然后在组合集上使用 connect by。

    另外,由于某种原因,Oracle 给第一个循环一个与其他循环不同的级别,因为它是一个自引用。我假设如果这是一个问题,您可以为此案例添加一些自定义逻辑。

    【讨论】:

    • 嗨 Craig,标签交换没有问题,吃掉这些数据的系统不在乎。 Ups 4 应该是 5 的附属,而不是相反,优秀的捕获。总而言之,出色的工作,超过了我的就寝时间,但稍后会对其进行测试并提供更多反馈。现在任何更改都应该很容易:)
    • 似乎我仍然遇到问题,如上所述。带有“null parent_id”的查询部分,如果我理解正确,我不需要没有更多 aff 的公司的输出 id
    【解决方案3】:

    未经测试。首先创建一个视图以简化从 2 个表中提取数据的过程。

    create view related(orgid, relatedid) as 
        select orgid, org_immediate_parent_orgid as relatedid from organizations
        union distinct
        select orgid, affiliated_orgid as relatedid from affiliated;
    

    现在我们可以使用它轻松地迭代查找所有有趣的 orgid。

    with recursive related_recursive(orgid, relatedid) as (
        select orgid, relatedid from related where relatedid = 2
        union
        select r.origid, rr.relatedid from related_recursive rr, related r
            where rr.orig = r.relatedid
    ) 
    select orgid from related_recursive;
    

    在这种情况下,您甚至可以删除related_recursive 的relatedid 列,但这很有用 如果您想删除或更改 where 部分并从 related_recursive 中选择 *,则这是必需的。

    请记住,CTE 会在主查询之前进行全面评估,因此这可能会拉入很多页面 在主查询中最终过滤之前。

    【讨论】:

    • 我没有看到你使用过connect by,我认为这是oracle特有的?如果 oracle 还不支持它,那么从标准的“递归”转换它应该没有问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 2016-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多