Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
具有多个表的Oracle CONNECT BY_Oracle_Oracle11g_Hierarchical Data - Fatal编程技术网

具有多个表的Oracle CONNECT BY

具有多个表的Oracle CONNECT BY,oracle,oracle11g,hierarchical-data,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 0047

我有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
我希望获得组件中使用的所有组件及其供应商和订单号(编辑:添加位置):

我的想法是将SELECT与connectby结合使用,但我无法让它正常工作

我当前的方法(编辑:根据GurV的输入进行更新):


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

如果我遵循您的逻辑,您可以使用而不是分层查询,这使得循环等更容易处理:

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
锚定成员直接从程序集数据中获取前两行,包括该表中的位置——这基本上是原始(pre-Gurv)查询,加上位置

递归成员然后查看作为
子compid
存在的每个生成行的
compid
,并将其位置附加到父行,同时从其他表中获取其他相关数据

如果要保留问题中显示的顺序,可以向递归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

如果我遵循您的逻辑,您可以使用而不是分层查询,这使得循环等更容易处理:

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
锚定成员直接从程序集数据中获取前两行,包括该表中的位置——这基本上是原始(pre-Gurv)查询,加上位置

递归成员然后查看作为
子compid
存在的每个生成行的
compid
,并将其位置附加到父行,同时从其他表中获取其他相关数据

如果要保留问题中显示的顺序,可以向递归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

标准的分层查询可以解决这个问题。我在您想要的输出中看到,您没有一列用于
assyid
;如果您的业务中有多个程序集,则这是一个缺陷。此外,我认为在某一点上,您需要计算组件的子组件的总数量(例如,组件a和组件b中都使用了螺钉,这两个组件都是组件1000的一部分,您需要螺钉的总数);但是,由于您希望以“适当的层次结构”(如
pos
列所示)显示所有内容,因此您似乎对此不感兴趣,至少在这个查询中不感兴趣使用标准的分层查询更难做到这一点,而在递归查询中更容易做到这一点,但这里的情况似乎并非如此

其思想是在
complist
assembly
之间
联合所有
,添加一个
标志
列以在分层查询的
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.

标准的分层查询可以解决这个问题。我在您想要的输出中看到,您没有一列用于
assyid
;如果您的业务中有多个程序集,则这是一个缺陷。此外,我认为在某一点上,您需要计算组件的子组件的总数量(例如,组件a和组件b中都使用了螺钉,这两个组件都是组件1000的一部分,您需要螺钉的总数);但是,由于您希望以“适当的层次结构”(如
pos
列所示)显示所有内容,因此您似乎对此不感兴趣,至少在这个查询中不感兴趣使用标准的分层查询更难做到这一点,而在递归查询中更容易做到这一点,但这里的情况似乎并非如此

其思想是在
complist
assembly
之间
联合所有
,添加一个
标志
列以在分层查询的
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.

在这个问题中不应该有循环(一般来说,在这种类型的问题中)-如果有,数据一定是损坏的。分层查询的主要问题(在本例中这不是一个障碍)是,它们在多个级别上不保留“先前状态”,因此,例如,如果我们必须在某个位置计算总量,我们必须收集字符串中的数量,将其拆分等-这是一个巨大的难题,递归查询将是自然的答案。这个问题似乎有一个标准的分层查询解决方案。@mathguy-就我个人而言,我仍然更喜欢递归CTE。主要是因为我发现它们更容易、更清晰;但它们也更标准(这对我来说并不重要,因为我只使用Oracle,但仍然…)。我认为CTE可能会更昂贵,但如果有那么多数据,我还是会对它们进行评估。我也喜欢递归CTE,特别是因为它们允许您创建和跟踪更多信息,而这些信息不在“输入”行集(或“行包”)的列中。然而,我发现,当这两种解决方案都可以使用时,分层查询的速度通常要快得多。然后,我专门使用Oracle,我甚至不知道——分层查询严格来说是Oracle的东西吗,比如外部联接的(+)符号和NVL?如果是的话,这是一个非常好的支持递归查询的参数。特别是在这个问题上,一个表可以放在锚分支中,另一个表可以放在递归分支中,这真是太好了。{:-)关于排序:您可以在第一个查询中完成,只需稍加修改