Oracle 中的分层 SQL

hierarchic SQL in Oracle

我有很多 table 列,所以为了简单起见,我只选择了相关的列。

有组件和模块。组件可以用作最终产品,但可以构建在另一个组件 = modul 中。模块也是如此。一个模块可以作为最终产品,也可以构建在另一个组件中 = modul.

在真实的 table 中只有数字,但为了更好地理解,我使用关系 component-modul 所以例如 componentA + componentB = modulAB 但 componentA 也可以用作最终项目。 因此在 table 中有 2 列标识组件是否正在使用,比如说作为工厂中的最终项目 assembly_id - 表示该项目是一个模块,因此必须有一些组件(孩子) in_assembly_id - 意味着这个项目将被构建在另一个项目/模块中

如上所述,项目可以是最终的,在这种情况下,两列都有 -1,但同时该项目可以构建在另一个项目(模块)中,因此还有另一行包含列 in_assembly_id < > -1 .在我的示例中 componentA

这同样适用于已经是具有某些组件的模块并且可以是最终项目或将构建在另一个项目(模块)中的项目(在_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

我从 c​​onnect 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 , 'componentA' , -1 , 50 );
insert into items values ( 3 , 'componentB' , -1 , 50 );
insert into items values ( 4 , 'modulAB' , 50 , -1 );
insert into items values ( 5 , 'componentA' , -1 , 100 );
insert into items values ( 6 , 'componentC' , -1 , 100);
insert into items values ( 7 , 'modulAC' , 100 , -1 );
insert into items values ( 7 , 'modulAC' , 100 , 500 );
insert into items values ( 8 , 'componentD' , -1 , 200 );
insert into items values ( 9 , 'componentE' , -1 , 200 );
insert into items values ( 10 , 'modulDE' , 200 , 500 );
insert into items values ( 11 , 'modulACDE' , 500 , -1 );
insert into items values ( 12 , 'componentF' , -1 , -1 );
insert into items values ( 13 , 'componentG' , -1 , -1 );

my goal is to find for particular item the modul item , doesn't matter that the item can be as final product as well

这将获得 componentA 的所有 modul:

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 | ,2,4,5,7     | ,componentA,modulAB,componentA,modulAC
           2 | componentA |       7 | modulAC   |         100 | ,2,4,6,7     | ,componentA,modulAB,componentC,modulAC
           2 | componentA |      10 | modulDE   |         200 | ,2,4,8,10    | ,componentA,modulAB,componentD,modulDE
           2 | componentA |      10 | modulDE   |         200 | ,2,4,9,10    | ,componentA,modulAB,componentE,modulDE
           5 | componentA |       7 | modulAC   |         100 | ,5,7         | ,componentA,modulAC                   
           5 | componentA |      10 | modulDE   |         200 | ,5,7,8,10    | ,componentA,modulAC,componentD,modulDE
           5 | componentA |      10 | modulDE   |         200 | ,5,7,9,10    | ,componentA,modulAC,componentE,modulDE
           5 | componentA |       7 | modulAC   |         100 | ,5,7         | ,componentA,modulAC                   
           5 | componentA |      11 | modulACDE |         500 | ,5,7,11      | ,componentA,modulAC,modulACDE         

db<>fiddle here


更新

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
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 | ,2,4         | ,componentA,modulAB          
           5 | componentA |       7 | modulAC   |         100 | ,5,7         | ,componentA,modulAC          
           5 | componentA |       7 | modulAC   |         100 | ,5,7         | ,componentA,modulAC          
           5 | componentA |      11 | modulACDE |         500 | ,5,7,11      | ,componentA,modulAC,modulACDE

db<>fiddle here