带有多个表的Oracle CONNECT BY

时间:2017-01-30 11:00:02

标签: oracle oracle11g hierarchical-data

我有4个表格包含我的数据:

Table COMP: definition of my component data
COMPID  | NAME      | DESCRIPTION
--------+-----------+------------
000123  | Comp. 1   | A44.123
000277  | Comp. 2   | A96.277
000528  | Comp. 3   | 1235287
001024  | Comp. 4   | Lollipop
004711  | Comp. 5   | Yippie

Table COMPLIST: containing the sub-components of each component
COMPID  | POS  | SUBCOMPID   | QUANTITY
--------+------+------------ +-----------
000123  | 1    | 000277      | 3
000123  | 2    | 000528      | 1
000528  | 1    | 004711      | 1

Table COMPSUPPLIER: definition of the components suppliers
COMPID  | SUPPLIER  | ORDERNUMBER
--------+-----------+-------------
000123  | Supp1     | A44.123
000277  | Supp1     | A96.277
000528  | Supp2     | 1235287
001024  | Supp2     | ux12v39
004711  | Supp1     | 123456

Table ASSEMBLY: definition of my assembly
ASSYID  | POS  | COMPID  | QUANTITY
--------+------+---------+----------
5021    | 1    | 000123  | 1
5021    | 2    | 001024  | 2

我想获得装配中使用的所有组件及其供应商和订单号(编辑:添加位置):

POS    | COMPID  | NAME    | SUPPLIER | ORDERNUMBER | QUANTITY
-------|---------+---------+----------+-------------+----------
1      | 000123  | Comp. 1 | Supp1    | A44.123     | 1
1.1    | 000277  | Comp. 2 | Supp1    | A96.277     | 3
1.2    | 000528  | Comp. 3 | Supp2    | 1235287     | 1
1.2.1  | 004711  | Comp. 5 | Supp1    | 123456      | 1
2      | 001024  | Comp. 4 | Supp2    | ux12v39     | 2

我的想法是将SELECT与CONNECT BY结合使用,但我无法正常使用。

我目前的做法(编辑:使用GurV输入更新):

SELECT c.COMPID, c.NAME, cs.SUPPLIER, cs.ORDERNUMBER
FROM COMP c
JOIN COMPSUPPLIER cs ON c.COMPID = cs.COMPID
WHERE c.COMPID in (
    SELECT COMPID
    FROM ASSEMBLY
    WHERE ASSYID = '5021'
    UNION ALL
    SELECT SUBCOMPID
    FROM COMPLIST
    CONNECT BY NOCYCLE PRIOR SUBCOMPID = COMPID
    START WITH COMPID in (
      SELECT COMPID
      FROM ASSEMBLY
      WHERE ASSYID = '5402')
);

有了这个,我得到了所有的子组件,但不是位置。是否有可能以某种方式得到职位栏?

2 个答案:

答案 0 :(得分:3)

如果我遵循您的逻辑,您可以使用recursive subquery factoring而不是分层查询,这会使周期等更容易应对:

with rcte (position, compid, name, supplier, ordernumber, quantity) as (
  select to_char(a.pos), a.compid, c.name, cs.supplier, cs.ordernumber, a.quantity
  from assembly a
  join compsupplier cs on cs.compid = a.compid
  join comp c on c.compid = cs.compid
  where a.assyid = 5021
  union all
  select rcte.position ||'.' || cl.pos, cl.subcompid, c.name,
    cs.supplier, cs.ordernumber, cl.quantity
  from rcte
  join complist cl on cl.compid = rcte.compid
  join compsupplier cs on cs.compid = cl.subcompid
  join comp c on c.compid = cs.compid  
)
select *
from rcte;

POSITION   COMPID NAME    SUPPL ORDERNU   QUANTITY
---------- ------ ------- ----- ------- ----------
1          000123 Comp. 1 Supp1 A44.123          1
2          001024 Comp. 4 Supp2 ux12v39          2
1.1        000277 Comp. 2 Supp1 A96.277          3
1.2        000528 Comp. 3 Supp2 1235287          1
1.2.1      004711 Comp. 5 Supp1 123456           1

锚点成员直接从装配数据中获取前两行,包括该表中的位置 - 基本上是您的原始(前Gurv)查询,加上位置。

然后,递归成员会查看complist每个生成的行compid作为subcompid存在,并将其位置附加到父级,同时获取来自其他表的其他相关数据。

如果您想在问题中显示订单时保留订单,可以在递归CTE中添加其他列,以跟踪原始位置和您当前所处的级别(可能还有其他信息可以打破关系) ,如果可能的话),并将其从最终选择列表中排除:

with rcte (position, compid, name, supplier, ordernumber, quantity,
    order_by_1, order_by_2)
as (
  select to_char(a.pos), a.compid, c.name, cs.supplier, cs.ordernumber, a.quantity,
    a.pos, 1
  from assembly a
  join compsupplier cs on cs.compid = a.compid
  join comp c on c.compid = cs.compid
  where a.assyid = 5021
  union all
  select rcte.position ||'.' || cl.pos, cl.subcompid, c.name,
    cs.supplier, cs.ordernumber, cl.quantity,
    rcte.order_by_1, rcte.order_by_2 + 1
  from rcte
  join complist cl on cl.compid = rcte.compid
  join compsupplier cs on cs.compid = cl.subcompid
  join comp c on c.compid = cs.compid  
)
select position, compid, name, supplier, ordernumber, quantity
from rcte
order by order_by_1, order_by_2;

POSITION   COMPID NAME    SUPPL ORDERNU   QUANTITY
---------- ------ ------- ----- ------- ----------
1          000123 Comp. 1 Supp1 A44.123          1
1.1        000277 Comp. 2 Supp1 A96.277          3
1.2        000528 Comp. 3 Supp2 1235287          1
1.2.1      004711 Comp. 5 Supp1 123456           1
2          001024 Comp. 4 Supp2 ux12v39          2

答案 1 :(得分:2)

标准分层查询将适用于此问题。我在您想要的输出中看到您没有assyid的列;如果您的企业中有多个装配,那就是一个缺陷。此外,我想在某些时候你会想要计算一个组件的子组件的总量(比如,螺钉用于组件a和组件b,两个组件都是组件1000,你需要总数螺钉数量);但是,既然你想要在适当的层次结构中展示所有东西并且#34; (如pos列中所示),您似乎对此并不感兴趣,至少在此查询中是这样。 那个对标准的分层查询更难做,而且在递归查询中更容易做,但在这里似乎并非如此。

我们的想法是在union allcomplist之间assembly,添加flag列以在分层查询的start with子句中使用。其他一切都很标准。

with 
     comp ( compid, name, description ) as (
       select '000123', 'Comp. 1', 'A44.123'  from dual union all
       select '000277', 'Comp. 2', 'A96.277'  from dual union all
       select '000528', 'Comp. 3', '1235287'  from dual union all
       select '001024', 'Comp. 4', 'Lollipop' from dual union all
       select '004711', 'Comp. 5', 'Yippie'   from dual
     ),
     Complist ( compid, pos, subcompid, quantity ) as (
       select '000123', 1, '000277', 3 from dual union all
       select '000123', 2, '000528', 1 from dual union all
       select '000528', 1, '004711', 1 from dual
     ),
     compsupplier ( compid, supplier, ordernumber ) as (
       select '000123', 'Supp1', 'A44.123' from dual union all
       select '000277', 'Supp1', 'A96.277' from dual union all
       select '000528', 'Supp2', '1235287' from dual union all
       select '001024', 'Supp2', 'ux12v39' from dual union all
       select '004711', 'Supp1', '123456'  from dual
     ),
     assembly ( assyid, pos, compid, quantity ) as (
       select '5021', 1, '000123', 1 from dual union all
       select '5021', 2, '001024', 2 from dual
     )
select h.assyid, ltrim(h.pos, '.') as pos, h.compid,
       c.name, s.supplier, s.ordernumber, h.quantity
from   (
         select subcompid as compid, quantity, 
                connect_by_root compid as assyid,
                sys_connect_by_path(pos, '.') as pos
         from   ( select complist.*, 'f'  as flag from complist
                  union all
                  select assembly.*, null as flag from assembly
                )
         start with flag is null
         connect by compid = prior subcompid
       ) h
       left outer join comp         c on h.compid = c.compid
       left outer join compsupplier s on h.compid = s.compid
;

<强>输出

ASSYID POS      COMPID NAME    SUPPLIER ORDERNUMBER   QUANTITY
------ -------- ------ ------- -------- ----------- ----------
5021   1        000123 Comp. 1 Supp1    A44.123              1
5021   1.1      000277 Comp. 2 Supp1    A96.277              3
5021   1.2      000528 Comp. 3 Supp2    1235287              1
5021   1.2.1    004711 Comp. 5 Supp1    123456               1
5021   2        001024 Comp. 4 Supp2    ux12v39              2

5 rows selected.