2011-01-24 79 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