具有多个表的 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) 查询,加上位置。
递归成员然后查看每个生成行的 compid
的 complist
作为 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
列中所反映),您似乎对此不感兴趣,至少在此查询中是这样。 使用标准的分层查询会更难,而在递归查询中更容易,但这里似乎并非如此。
思路是在complist
和assembly
之间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.
我有 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) 查询,加上位置。
递归成员然后查看每个生成行的 compid
的 complist
作为 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
列中所反映),您似乎对此不感兴趣,至少在此查询中是这样。 使用标准的分层查询会更难,而在递归查询中更容易,但这里似乎并非如此。
思路是在complist
和assembly
之间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.