【问题标题】:Build a tree from Oracle tables从 Oracle 表构建树
【发布时间】:2016-04-04 19:05:45
【问题描述】:

我在 Oracle 中有两个表用于表示各种树,这些表是:“PARTS_TREE_ENTRIES”存储所有节点(包括父节点和子节点),“PARTS_ITEMS”描述节点之间的关系

在表 TREE_ITEMS 中,列 COMPONENT_ID 代表父亲,COMPONENT_ITEMID 代表其孩子

有不止一棵树,所有树的节点都在同一个表“TREE_ENTRIES”中为了更容易理解,这是几棵树的表示:

这些是他们在表格中的条目:

正如您在表 TREE_ITEMS 中看到的那样,作为分支根节点的 COMPONENT_ID 的值为“A”

我需要帮助来构建查询以获取最后一级的所有节点及其父级及其 ID 的列表,输出应类似于以下内容:

我已经阅读过“连接方式”子句,但我从未使用过它,我不知道从哪里开始。

非常感谢您!

【问题讨论】:

  • 如果您的输出始终基于三层树,那么您选择的架构可能不是最合适的。
  • 据了解,这棵树只有三个级别,但它最终可能会得到新的级别,这就是我选择此架构的原因,但我想听听您的理由。

标签: oracle tree hierarchical-data recursive-query


【解决方案1】:

我知道您明确询问了通过查询连接的问题,但我认为我们可以练习使用带有 SQL 的递归,因为它可以通过一些附加功能完成相同的工作。

根据您的示例结果,我的最佳猜测是这样的。

我不清楚您是想要连接数据还是分隔列,所以对这两种情况都有建议。

with tree_view(tree_id, component_id, component_itemid, id, part_tree_id, componentid, name, lvl, tree_path, root_id) as (
select t.tree_id, t.component_id, t.component_itemid, t.id, e.part_tree_id, e.componentid, e.name, 1, e.name, component_itemid
  from tree_items t,
       tree_entries e
 where t.component_itemid = e.componentid
   and t.tree_id = e.part_tree_id
   and t.component_id = 'A'
union all
select t.tree_id, t.component_id, t.component_itemid, t.id, e.part_tree_id, e.componentid, e.name, tv.lvl + 1, tv.tree_path || '=>' || e.name, tv.root_id
  from tree_items t,
       tree_entries e,
       tree_view tv
 where to_char(tv.component_itemid) = to_char(t.component_id)
       and to_char(e.componentid) = to_char(t.component_itemid)
       and tv.tree_id = t.tree_id
) -- end of hierarchy view
search depth first by lvl set order1
select tree_path,
       name,
       componentid,
       regexp_substr(tree_path, '[[:alpha:]]+', 1, 1) lvl1_part,
       regexp_substr(tree_path, '[[:alpha:]]+', 1, 2) lvl2_part,
       regexp_substr(tree_path, '[[:alpha:]]+', 1, 3) lvl3_part -- add more if there are further levels down the tree
  from (
        select tree_id, component_id, component_itemid, id, part_tree_id, componentid, name, lvl, tree_path, root_id, order1,
               case when lvl - lead(lvl) over (order by order1) < 0 then 0 else 1 end is_leaf
          from tree_view
       )
 where is_leaf = 1;

这是使用您提供的数据在 Oracle 上执行的示例:

Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 
Connected as sitja@orasitja

SQL> 
SQL> col tree_path format a40
SQL> col lvl1_part format a20
SQL> col lvl2_part format a20
SQL> col lvl3_part format a20
SQL> drop table tree_entries;
Table dropped
SQL> create table  tree_entries as
  2  with tree_entries(part_tree_id, componentid, name) as (
  3  select 1, 101, 'CLOCK' from dual union all
  4  select 1, 102, 'WATCH' from dual union all
  5  select 1, 105, 'BAND' from dual union all
  6  select 1, 113, 'MATERIAL' from dual union all
  7  select 1, 114, 'COLOR' from dual union all
  8  select 1, 106, 'CASE' from dual union all
  9  select 1, 115, 'MATERIAL' from dual union all
 10  select 1, 116, 'SHAPE' from dual union all
 11  select 1, 107, 'BEZEL' from dual union all
 12  select 1, 117, 'MATERIAL' from dual union all
 13  select 1, 118, 'TEXTURE' from dual union all
 14  select 1, 108, 'FACE' from dual union all
 15  select 1, 119, 'SHAPE' from dual union all
 16  select 1, 120, 'DESIGN' from dual union all
 17  select 2, 103, 'RELOJ' from dual union all
 18  select 2, 104, 'RELOJPULSERA' from dual union all
 19  select 2, 109, 'CORREA' from dual union all
 20  select 2, 121, 'MATERIAL' from dual union all
 21  select 2, 122, 'COLOR' from dual union all
 22  select 2, 110, 'CAJA' from dual union all
 23  select 2, 123, 'MATERIAL' from dual union all
 24  select 2, 124, 'FORMA' from dual union all
 25  select 2, 111, 'BISEL' from dual union all
 26  select 2, 125, 'MATERIAL' from dual union all
 27  select 2, 126, 'TEXTURA' from dual union all
 28  select 2, 112, 'CARATULA' from dual union all
 29  select 2, 127, 'FORMA' from dual union all
 30  select 2, 128, 'DISEÑO' from dual
 31  )
 32  select * from tree_entries;
Table created
SQL> drop table tree_items;
Table dropped
SQL> create table  tree_items as
  2  with tree_items(tree_id, component_id, component_itemid, id) as (
  3  select 1, 'A', 101, 1 from dual union all
  4  select 1, 'A', 102, 2 from dual union all
  5  select 1, '101', 107, 3 from dual union all
  6  select 1, '101', 108, 4 from dual union all
  7  select 1, '102', 105, 5 from dual union all
  8  select 1, '102', 106, 6 from dual union all
  9  select 1, '107', 117, 7 from dual union all
 10  select 1, '107', 118, 8 from dual union all
 11  select 1, '108', 119, 9 from dual union all
 12  select 1, '108', 120, 10 from dual union all
 13  select 1, '105', 113, 11 from dual union all
 14  select 1, '105', 114, 12 from dual union all
 15  select 1, '106', 115, 13 from dual union all
 16  select 1, '106', 116, 14 from dual union all
 17  select 2, 'A', 103, 15 from dual union all
 18  select 2, 'A', 104, 26 from dual union all
 19  select 2, '103', 111, 33 from dual union all
 20  select 2, '103', 112, 42 from dual union all
 21  select 2, '104', 109, 54 from dual union all
 22  select 2, '104', 110, 62 from dual union all
 23  select 2, '111', 125, 74 from dual union all
 24  select 2, '111', 126, 82 from dual union all
 25  select 2, '112', 127, 91 from dual union all
 26  select 2, '112', 128, 10 from dual union all
 27  select 2, '109', 127, 114 from dual union all
 28  select 2, '109', 122, 122 from dual union all
 29  select 2, '110', 123, 3334 from dual union all
 30  select 2, '110', 124, 141 from dual
 31  )
 32  select * from tree_items;
Table created
SQL> with tree_view(tree_id, component_id, component_itemid, id, part_tree_id, componentid, name, lvl, tree_path, root_id) as (
  2  select t.tree_id, t.component_id, t.component_itemid, t.id, e.part_tree_id, e.componentid, e.name, 1, e.name, component_itemid
  3    from tree_items t,
  4         tree_entries e
  5   where t.component_itemid = e.componentid
  6     and t.tree_id = e.part_tree_id
  7     and t.component_id = 'A'
  8  union all
  9  select t.tree_id, t.component_id, t.component_itemid, t.id, e.part_tree_id, e.componentid, e.name, tv.lvl + 1, tv.tree_path || '=>' || e.name, tv.root_id
 10    from tree_items t,
 11         tree_entries e,
 12         tree_view tv
 13   where to_char(tv.component_itemid) = to_char(t.component_id)
 14         and to_char(e.componentid) = to_char(t.component_itemid)
 15         and tv.tree_id = t.tree_id
 16  ) -- end of hierarchy view
 17  search depth first by lvl set order1
 18  select tree_path,
 19         name,
 20         componentid,
 21         regexp_substr(tree_path, '[[:alpha:]]+', 1, 1) lvl1_part,
 22         regexp_substr(tree_path, '[[:alpha:]]+', 1, 2) lvl2_part,
 23         regexp_substr(tree_path, '[[:alpha:]]+', 1, 3) lvl3_part -- add more if there are further levels down the tree
 24    from (
 25          select tree_id, component_id, component_itemid, id, part_tree_id, componentid, name, lvl, tree_path, root_id, order1,
 26                 case when lvl - lead(lvl) over (order by order1) < 0 then 0 else 1 end is_leaf
 27            from tree_view
 28         )
 29   where is_leaf = 1;
TREE_PATH                                NAME         COMPONENTID LVL1_PART            LVL2_PART            LVL3_PART
---------------------------------------- ------------ ----------- -------------------- -------------------- --------------------
CLOCK=>BEZEL=>MATERIAL                   MATERIAL             117 CLOCK                BEZEL                MATERIAL
CLOCK=>BEZEL=>TEXTURE                    TEXTURE              118 CLOCK                BEZEL                TEXTURE
CLOCK=>FACE=>SHAPE                       SHAPE                119 CLOCK                FACE                 SHAPE
CLOCK=>FACE=>DESIGN                      DESIGN               120 CLOCK                FACE                 DESIGN
WATCH=>BAND=>MATERIAL                    MATERIAL             113 WATCH                BAND                 MATERIAL
WATCH=>BAND=>COLOR                       COLOR                114 WATCH                BAND                 COLOR
WATCH=>CASE=>MATERIAL                    MATERIAL             115 WATCH                CASE                 MATERIAL
WATCH=>CASE=>SHAPE                       SHAPE                116 WATCH                CASE                 SHAPE
RELOJ=>BISEL=>MATERIAL                   MATERIAL             125 RELOJ                BISEL                MATERIAL
RELOJ=>BISEL=>TEXTURA                    TEXTURA              126 RELOJ                BISEL                TEXTURA
RELOJ=>CARATULA=>FORMA                   FORMA                127 RELOJ                CARATULA             FORMA
RELOJ=>CARATULA=>DISEÑO                  DISEÑO               128 RELOJ                CARATULA             DISEÑO
RELOJPULSERA=>CORREA=>COLOR              COLOR                122 RELOJPULSERA         CORREA               COLOR
RELOJPULSERA=>CORREA=>FORMA              FORMA                127 RELOJPULSERA         CORREA               FORMA
RELOJPULSERA=>CAJA=>MATERIAL             MATERIAL             123 RELOJPULSERA         CAJA                 MATERIAL
RELOJPULSERA=>CAJA=>FORMA                FORMA                124 RELOJPULSERA         CAJA                 FORMA
16 rows selected

SQL> 

【讨论】:

  • 嗨弗朗西斯科,你建议的解决方案非常有效,尽管老实说我很难理解它,因为我的 SQL 水平不是很好,我会花一些有趣的时间来分析它。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多