具有多个表的 Oracle CONNECT BY

Oracle CONNECT BY with multiple tables

我有 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')
);

有了这个,我得到了我所有的子组件,但没有位置。是否有可能以某种方式也获得位置列?

如果我遵循你的逻辑,你可以使用 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

锚成员直接从程序集数据中获取前两行,包括来自 table 的位置 - 这基本上是您的原始 (pre-Gurv) 查询,加上位置。

递归成员然后查看每个生成行的 compidcomplist 作为 subcompid 存在,并将其位置附加到父级的同时从另一个获取其他相关数据tables.

如果您想保留您在问题中显示的顺序,您可以向递归 CTE 添加额外的列来跟踪原始位置和您当前所在的级别(可能与其他信息一起打破平局,如果可能的话),并从最终的 select 列表中排除那些:

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

标准的分层查询可以解决这个问题。我在您想要的输出中看到您没有 assyid 的列;如果您的企业中有多个组件,那就是一个缺陷。另外,我想在某些时候你会想要计算一个组件的 sub-component 的总量(比如,组件 a 和组件 b 中都使用了螺钉,两者都是组件 1000 的一部分,你需要螺钉总数);但是,由于您想显示所有内容 "in its proper hierarchy"(如 pos 列中所反映),您似乎对此不感兴趣,至少在此查询中是这样。 使用标准的分层查询会更难,而在递归查询中更容易,但这里似乎并非如此。

思路是在complistassembly之间union all,增加一个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.