2011-01-24 57 views
2

我有一个有趣的SQL问题。我有一个分层的表格来制作材料清单。与此类似:帮助计算分层数据集中的复杂总和

ASSEMBLY 
--------- 
parent_part_id 
part_id 
quantity 

我得到这个结构的层次,像这样的查询:

SELECT level, part_id, quantity 
from assembly 
start with parent_part_id = 1 
connect by parent_part_id = prior part_id; 

输出可能是这样的:

level part_id quantity 
----- ------- --------- 
1  2  2 
2  3  10 
1  4  2 
2  5  1  
3  3  5 

到目前为止好。

问题是这样的:我如何计算为了制作顶层装配(第1部分)而需要的每个零件的总数?

按部分对该结果集合进行分组并对数量进行求和是不正确的,因为数量应该乘以紧接在层次结构中当前部分之上的部分的数量,递归地向上遍历树。

我在想这是一个LAG功能,但是很难将其可视化。

编辑:预计业绩:

part_id quantity 
------- -------- 
2  2 
3  30 
4  2 
5  2 

更多编辑:我得到有意思的结果与此查询

SELECT rownum, level lvl, part_id, quantity, unit_of_measure 
       , connect_by_isleaf || sys_connect_by_path(quantity,'*') math 
      from assembly 
      start with parent_part_id = 1 
      connect by parent_part_id = prior part_id 

数学列返回计算的字符串表示我想执行的:)它可能会说:

1*1*2*10 

或类似和适当的...也许做一个函数来解析这个并返回结果将解决问题..任何人都认为这太离谱了?

+0

我很抱歉,但我不明白的问题*我怎么计算,以使顶层组件(部分1)需要各部分的总数是多少?*,并在相关说明,你如何得出预期的结果。 – 2011-01-24 20:16:00

+0

@Rene - 第1部分是创建第一个平行结果的原始parent_part_id。如果我们看看这些结果,那么请注意,我们需要part_id 2中的2个,其中每个需要part_id 3中的10个 - 此分支对第3部分中的总数贡献20个,稍后以类似的方式需要10个第3部分,总共有30 – Randy 2011-01-24 20:24:13

回答

5

在Oracle 11 R2的可能有common table expression

测试数据:

-- drop table assembly; 

create table assembly (
    part_id    number, 
    parent_part_id  number, 
    quantity    number 
); 

insert into assembly values (2, 1, 2); 
insert into assembly values (3, 2, 10); 
insert into assembly values (4, 1, 2); 
insert into assembly values (5, 4, 1); 
insert into assembly values (3, 5, 5); 

select语句:

select 
    part_id, 
    sum(quantity_used) as quantity 
from (
    with assembly_hier (lvl, part_id, quantity, quantity_used) as (
    select 
     1  lvl, 
     part_id, 
     quantity , 
     quantity  quantity_used 
    from 
     assembly 
    where 
     parent_part_id = 1 
    union all 
    select 
     assembly_hier.lvl  + 1 lvl, 
     assembly  .part_id, 
     assembly  .quantity, 
     assembly_hier.quantity_used * assembly.quantity quantity_used 
    from 
     assembly_hier, assembly 
    where 
     assembly_hier.part_id = assembly.parent_part_id 
) 
    select * from assembly_hier 
) 
group by part_id 
order by part_id; 

编辑此前Ora11R2,它可能工作与一个model clause

select 
    part_id, 
    sum(quantity) quantity 
from (
    select 
    lvl 
    parent_part_id, 
    part_id, 
    quantity 
    from (
    select 
     lvl, 
     parent_part_id, 
     part_id, 
     quantity 
    from (
     select 
     rownum r, 
     level lvl, 
     parent_part_id, 
     part_id, 
     quantity 
     from 
     assembly 
     start with parent_part_id = 1 
     connect by parent_part_id = prior part_id 
    ) 
) 
    model 
    dimension by (lvl, part_id) 
    measures (quantity, parent_part_id) 
    rules upsert (
     quantity[  any, any   ] order by lvl, part_id = quantity[cv(lvl) , cv(part_id)] * 
              nvl(quantity[cv(lvl)-1, parent_part_id[cv(lvl), cv(part_id)] ], 1) 
    ) 
) 
group by part_id 
order by part_id; 

编辑II另一种可能性是,总结量的对数,然后采取总和的指数:

select 
    part_id, 
    sum(quantity) quantity 
from (
    select 
    part_id, 
    exp(sum(quantity_ln) over (partition by new_start order by r)) quantity 
    from (
    select 
     r, 
     lvl, 
     part_id, 
     quantity_ln, 
     sum(new_start) over(order by r) new_start 
    from (
     select 
     rownum r, 
     level lvl, 
     part_id, 
     ln(quantity) quantity_ln, 
     nvl(lag(connect_by_isleaf,1) over (order by rownum),0) new_start 
     from assembly 
     start with parent_part_id = 1 
     connect by parent_part_id = prior part_id 
    ) 
) 
) 
group by part_id 
order by part_id 
; 
0

我在这里结束了:这个作品在Oracle 10和11,CONNECT_BY_ISLEAF可以使用调整逻辑,无论您是只求和叶子还是所有节点。

select part_id, new_rec.quantity*sum(math_calc(math,2)) m, unit_of_measure 
from (SELECT rownum, level lvl, part_id, quantity, unit_of_measure 
      , connect_by_isleaf || sys_connect_by_path(quantity,'*') math 
from assembly 
start with parent_part_id = new_rec.part_id 
connect by parent_part_id = prior part_id) p 
group by part_id, unit_of_measure