我有一个有趣的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 :(得分: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
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
;
答案 1 :(得分: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