多个表的层次结构查询

时间:2017-08-16 07:37:49

标签: sql oracle hierarchical-data

我有一个主表,其中包含客户,零售商,fse,dist和sub dist的所有详细信息。 我需要设计层次结构 cust(1) - > ret(2) - > fse(3) - > dist(4) - > sub dist(5) 表 master_table:

id    cust_mobile    type
1       9000230003   cust
2       8906784566   ret
3       7474747474   dist
4       4595274646   sdist
5       8588585958   fse
6       8588775958   cust
8       8588777758   dist

link_table

id  parent_id
1     2
2     8
3     7
4     5
6     3

我需要输出

1,9000230003,cust,2,8906784566,ret,8,8588777758,dist
6 8588775958 cust,3,7474747474,dist

我想要与1个客户ID相关联的所有级别。

2 个答案:

答案 0 :(得分:1)

如果你首先加入你的桌子:

select mt.id, mt.cust_mobile, mt.type, lt.parent_id
from master_table mt
left join link_table lt on lt.id = mt.id;

        ID CUST_MOBIL TYPE   PARENT_ID
---------- ---------- ----- ----------
         1 9000230003 cust           2
         2 8906784566 ret            8
         3 7474747474 dist           7
         4 4595274646 sdist          5
         6 8588775958 cust           3
         5 8588585958 fse             
         8 8588777758 dist            

然后,您可以使用分层查询作为内联视图或CTE,从任何'cust'条目开始:

with cte (id, cust_mobile, type, parent_id) as (
  select mt.id, mt.cust_mobile, mt.type, lt.parent_id
  from master_table mt
  left join link_table lt on lt.id = mt.id
)
select listagg(id ||','|| cust_mobile ||','|| type, ',')
  within group (order by level) as result
from cte
start with type = 'cust'
connect by id = prior parent_id
group by connect_by_root(id);

RESULT                                                                          
--------------------------------------------------------------------------------
1,9000230003,cust,2,8906784566,ret,8,8588777758,dist
6,8588775958,cust,3,7474747474,dist

这将每行的相关数据连接成一个用逗号分隔的值;然后使用listagg()将这些组合条目中的每一个放入单个结果中。

为了好玩,您还可以使用递归CTE(来自11gR2);我在CTE中移动了初始连接只是为了将它与listagg()分开:

with rcte (id, id_mobile_type, root_id, hop) as (
  select mt.id, mt.id ||','|| mt.cust_mobile ||','|| mt.type, mt.id, 1
  from master_table mt
  where mt.type = 'cust' -- starting condition
  union all
  select mt.id, mt.id ||','|| mt.cust_mobile ||','|| mt.type,
    rcte.root_id, rcte.hop + 1
  from rcte
  join link_table lt on lt.id = rcte.id
  join master_table mt on mt.id = lt.parent_id
)
select listagg(id_mobile_type, ',') within group (order by hop) as result
from rcte
group by root_id;

RESULT                                                                          
--------------------------------------------------------------------------------
1,9000230003,cust,2,8906784566,ret,8,8588777758,dist
6,8588775958,cust,3,7474747474,dist

答案 1 :(得分:0)

我真的明白来自@Alex Poole的解决方案更好,我投了赞成票。我只想添加使用SYS_CONNECT_BY_PATH

的硬编码查询

代码:

with t1 as (
    select 1 as id, 9000230003 as cust_mobile, 'cust' as type from dual
    union all
    select 2 as id, 8906784566 as cust_mobile, 'ret' as type from dual
    union all
    select 3 as id, 7474747474 as cust_mobile, 'dist' as type from dual
    union all
    select 4 as id, 4595274646 as cust_mobile, 'sdist' as type from dual
    union all
    select 5 as id, 8588585958 as cust_mobile, 'fse' as type from dual
    union all
    select 6 as id, 8588775958 as cust_mobile, 'cust' as type from dual
    union all
    select 8 as id, 8588777758 as cust_mobile, 'dist' as type from dual
    ),
    lt as (
    select 1 as id_, 2 as parent_id from dual
    union all
    select 2 as id_, 8 as parent_id from dual
    union all
    select 3 as id_, 7 as parent_id from dual
    union all
    select 4 as id_, 5 as parent_id from dual
    union all
    select 6 as id_, 3 as parent_id from dual
    )
    select replace(path,', ',',')
    from (
        select CONNECT_BY_ISLEAF as leaf, substr(SYS_CONNECT_BY_PATH(t2.id || ',' || t2.cust_mobile || ',' || t2.type, ', '),3) as path
        from  
        ( 
            select t1.*, lt.parent_id
            from t1 left join lt on t1.id = lt.id_ 
        ) t2 
        start with t2.type = 'cust' 
        connect by t2.id = prior t2.parent_id 
    ) t3
    where t3.leaf = 1

结果:

1,9000230003,cust,2,8906784566,ret,8,8588777758,dist
6,8588775958,cust,3,7474747474,dist