【问题标题】:Getting parent data if child data is null in Oracle hierarchical table如果Oracle分层表中的子数据为空,则获取父数据
【发布时间】:2014-09-20 14:31:34
【问题描述】:

在 Oracle 10g 中,我有以下分层表:

corp_id, parent_corp_id, col1, col2, col3

我想展平结构,以便我们获得第一行的数据,其中 col1 OR col2 OR col3 不为空。

例如,假设我有:

corp_id = 1
parent_corp_id = null
col1 = 5
col2 = NULL
col3 = NULL

corp_id = 3
parent_corp_id = 1
col1 = NULL
col2 = NULL
col3 = NULL

这个查询的结果会给我:

corp_id, parent_corp_id, col1, col2, col3
3      , 1             , 5   , NULL, NULL

另一种情况: 假设我把 col2 = 6 where corp_id = 3

那么,结果集应该是:

corp_id, parent_corp_id, col1, col2, col3
3      , 1             , NULL, 6,    NULL

换句话说,如果孩子在这三列之一中有数据,我们会抓取它。否则,我们尝试父母等等。深度不应超过 3 层,但可以有 3 层可供研究。

对分层查询很陌生,如果这是一个初级问题,请原谅我。

【问题讨论】:

    标签: sql oracle hierarchy connect-by


    【解决方案1】:

    使用coalesce() 函数,该函数返回其列表中的第一个非空值:

    select
        c.corp_id,
        c.parent_corp_id,
        coalesce(c.col1, p.col1) col1,
        coalesce(c.col2, p.col2) col2,
        coalesce(c.col3, p.col3) col3
    from mytable c
    left join mytable p on p.corp_id = c.parent_corp_id
    

    要获取“具有非空值的第一行”,请添加:

    where coalesce(c.col1, p.col1, c.col2, p.col2, c.col3, p.col3) is not null
    and rownum = 1
    

    【讨论】:

    • 恐怕这对我不起作用,我需要一个分层查询,因为我不知道在找到一个值之前我必须上升多少层......
    • @mlnyc 等级有上限吗?
    【解决方案2】:

    您确实需要使用分层查询(带有 connect by 子句),因为您有一个有孩子的父母并且该孩子是另一个孩子的父母(尽管您的示例数据没有带来发挥作用)但是,显示“first not null col1”和“first not null col2”等的要求完全是与层次关系不同的问题。

    尝试以下操作,我在小提琴中添加了一些额外的示例数据(检查左侧的 DDL)以进行说明。

    在您的预期输出中,您似乎不想显示最高级别的父母,这就是为什么我将“s.parent_corp_id 不为空”放在最后。如果你真的想展示这些,就把那条线去掉。

    否则,这将根据它们的组显示 col1/col2/col3 值。请注意,示例 2 是高级父级,有 4 个作为子级,4 也是 8 的父级。所以 corp_id 8 和 4 是同一分支的一部分,因此它们显示相同的 col1/col2/col3 值,根据您的要求,这些是整个分支中每个的第一个非空值。

    小提琴: http://sqlfiddle.com/#!4/ef218/14/0

    with sub as
     (select corp_id,
             parent_corp_id,
             col1,
             col2,
             col3,
             level as lvl,
             rownum - level as grp
        from tbl
      connect by prior corp_id = parent_corp_id
       start with parent_corp_id is null),
    col1_lvl as
     (select grp, col1
        from sub s
       where s.lvl = (select min(x.lvl)
                        from sub x
                       where x.col1 is not null
                         and x.grp = s.grp)),
    col2_lvl as
     (select grp, col2
        from sub s
       where s.lvl = (select min(x.lvl)
                        from sub x
                       where x.col2 is not null
                         and x.grp = s.grp)),
    col3_lvl as
     (select grp, col3
        from sub s
       where s.lvl = (select min(x.lvl)
                        from sub x
                       where x.col3 is not null
                         and x.grp = s.grp))
    select s.corp_id, s.parent_corp_id, c1.col1, c2.col2, c3.col3
      from sub s
      left join col1_lvl c1
        on s.grp = c1.grp
      left join col2_lvl c2
        on s.grp = c2.grp
      left join col3_lvl c3
        on s.grp = c3.grp
     where s.parent_corp_id is not null
    

    如果这没有根据我使用的示例数据提供您期望的输出,请为我在小提琴的 DDL 中使用的数据提供预期的输出。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-01
      • 1970-01-01
      相关资源
      最近更新 更多