Oracle中的分层SQL

问题描述

我的表很大,有很多列,为简单起见,我只选取了相关的列。

有组件和模块。组件可以用作最终产品,但可以内置在另一个组件=模块化中。模数也一样。一个模块可以作为最终产品,也可以内置在另一个组件中。

在实际表中只有数字,但是为了更好地理解,我使用了组件关系 因此,例如componentA + componentB = modulAB,但是componentA也可以用作最终项目。 因此,在表格中有2列用于标识组件是否正在用作工厂中的最终物料 assembly_id-表示该项目是模数,因此必须具有某些组件(子代) in_assembly_id-表示该项目将内置在另一个项目/模块中

如上所述,

在这两个列都为-1的情况下,它可以是最终的,但同时可以在另一个item(modul)中构建该项目,因此在我的示例中还有一行in_assembly_id -1的行。 componentA

对于已经用某些组件进行了模块化并且可以作为最终项目的项目,也可以将其内置在in_assembly_id列中指示的另一个项目(模块化)中。

我的目标是找到特定项目的模块化项目,无论该项目是否也可以作为最终产品

我可以使用join,但只能找到一个上级。

select distinct c.item,c.in_assembly_id,modul,modul_id from items c,lateral (select a.item modul,a.assembly_id modul_id from items a where a.assembly_id=c.in_assembly_id)
where c.item = 'componentA' and c.in_assembly_id <> -1;

ITEM        IN_ASSEMBLY_ID  MODUL   MODUL_ID
componentA  100             modulAC 100
componentA  50              modulAB 50

所以要查看整个结构,因为modulAC是内置在modulACDE中的,因此需要分层查询才能看到这样的输出 1。

ITEM        IN_ASSEMBLY_ID assembly_id type/level
componentA  -1             50          comp
modulAB     50             -1          modul
componentA  -1             100         comp
modulAC     100            -1          modul
modulAC     100            500         modul
modulACDE   500            -1          modul

最高模数

    ITEM        IN_ASSEMBLY_ID assembly_id type/level
    componentA  -1             50          comp
    modulAB     50             -1          modul
    componentA  -1             100         comp
    modulACDE   500            -1          modul

我从connect by子句开始,但是它对我不起作用,我不知道为什么得到modulDE

select distinct * from items
connect by nocycle in_assembly_id = prior assembly_id
start with item = 'componentA' and in_assembly_id <> '-1';

这是我的数据

create table items (
item_id number,item varchar2(12),assembly_id number,in_assembly_id number
);

insert into items values ( 1,'componentA',-1,-1 );
insert into items values ( 2,50 );
insert into items values ( 3,'componentB',50 );
insert into items values ( 4,'modulAB',50,-1 );
insert into items values ( 5,100 );
insert into items values ( 6,'componentC',100);
insert into items values ( 7,'modulAC',100,-1 );
insert into items values ( 7,500 );
insert into items values ( 8,'componentD',200 );
insert into items values ( 9,'componentE',200 );
insert into items values ( 10,'modulDE',200,500 );
insert into items values ( 11,'modulACDE',500,-1 );
insert into items values ( 12,'componentF',-1 );
insert into items values ( 13,'componentG',-1 );

解决方法

我的目标是为特定的商品找到modul的商品,这与该商品也可以作为最终商品无关紧要

这将获得modul的所有componentA

SELECT CONNECT_BY_ROOT( item_id ) AS root_item_id,CONNECT_BY_ROOT( item ) AS root_item,item_id,item,assembly_id,SYS_CONNECT_BY_PATH( item_id,',' ) AS path_item_id,SYS_CONNECT_BY_PATH( item,' ) AS path_item
FROM   items
WHERE  assembly_id <> -1
START WITH
       item = 'componentA'
AND    ( assembly_id,in_assembly_id ) NOT IN ((-1,-1))
CONNECT BY NOCYCLE
       PRIOR in_assembly_id = assembly_id
ORDER SIBLINGS BY item,item_id;

哪个输出:

ROOT_ITEM_ID | ROOT_ITEM  | ITEM_ID | ITEM      | ASSEMBLY_ID | PATH_ITEM_ID | PATH_ITEM                             
-----------: | :--------- | ------: | :-------- | ----------: | :----------- | :-------------------------------------
           2 | componentA |       4 | modulAB   |          50 |,2,4         |,componentA,modulAB                   
           2 | componentA |       7 | modulAC   |         100 |,4,5,7     |,modulAB,modulAC
           2 | componentA |       7 | modulAC   |         100 |,6,componentC,modulAC
           2 | componentA |      10 | modulDE   |         200 |,8,10    |,componentD,modulDE
           2 | componentA |      10 | modulDE   |         200 |,9,componentE,modulDE
           5 | componentA |       7 | modulAC   |         100 |,7         |,modulAC                   
           5 | componentA |      10 | modulDE   |         200 |,7,modulAC,modulDE
           5 | componentA |      10 | modulDE   |         200 |,modulAC                   
           5 | componentA |      11 | modulACDE |         500 |,11      |,modulACDE         

db 提琴here


更新

SELECT CONNECT_BY_ROOT( item_id ) AS root_item_id,' ) AS path_item
FROM   items
WHERE  assembly_id > -1
START WITH
       item = 'componentA'
AND    ( assembly_id,-1))
CONNECT BY NOCYCLE
       PRIOR in_assembly_id = assembly_id
AND    assembly_id > -1
ORDER SIBLINGS BY item,item_id;

输出:

ROOT_ITEM_ID | ROOT_ITEM  | ITEM_ID | ITEM      | ASSEMBLY_ID | PATH_ITEM_ID | PATH_ITEM                    
-----------: | :--------- | ------: | :-------- | ----------: | :----------- | :----------------------------
           2 | componentA |       4 | modulAB   |          50 |,modulAB          
           5 | componentA |       7 | modulAC   |         100 |,modulAC          
           5 | componentA |       7 | modulAC   |         100 |,modulAC          
           5 | componentA |      11 | modulACDE |         500 |,modulACDE

db 提琴here