Oracle聚合函数分配金额
Oracle aggregation function to allocate amount
假设我有 2 tables T1
和 T2
如下
T1
:
bag_id bag_type capacity
------|--------|--------
1 A 500
2 A 300
3 A 100
4 B 200
5 B 100
T2
:
item_type item_amount
---------|-----------
A 850
B 300
tableT1
中的每条记录代表一个包及其容量,这里我有5个包。我想写一个 SQL 将 table T2
中的项目分配到每个相同类型的包中,即结果应该是这样的
bag_id bag_type capacity allocated_amount
------|--------|--------|----------------
1 A 500 500
2 A 300 300
3 A 100 50
4 B 200 200
5 B 100 100
因此,我正在寻找某种聚合函数,我们称它为 allocate()
,它可以生成如上所述的列 allocated_amount
。 我有猜测,如果存在,可能会像这样使用
select
t1.bag_id,
t1.bag_type,
t1.capacity,
allocate(t2.item_amount, t1.capacity)
over (partition by t1.bag_type order by t1.capacity desc) as allocatd_amount
from t1, t2
where t2.item_type = t1.bag_type
我目前的解决方案是使用临时 table 和 PL/SQL 循环进行计算,但我希望我可以用一个简单的 SQL.
来完成
您正在查找累计金额。像这样:
select t1.*,
(case when cumecap <= t2.item_amount
then t1.capacity
when cumecap - t1.capacity <= t2.item_amount
then t2.item_amount - (cumecap - t1.capacity)
else 0
end) as allocated_capacity
from (select t1.*,
sum(t1.capacity) over (partition by bag_type order by bag_id) as cumecap
from t1
) t1 join
t2
on t1.bag_type = t2.item_type;
假设按照包容量的降序分配
with agg as (
select bag.BAG_ID, bag.BAG_TYPE, bag.CAPACITY,
SUM(bag.CAPACITY) over (partition by bag.bag_type order by bag.capacity DESC) agg_capacity,
item_amount
from bag, item
where bag.bag_type = item.item_type
)
select
BAG_ID, BAG_TYPE, CAPACITY,
case when ITEM_AMOUNT >= AGG_CAPACITY then CAPACITY /* Full allocated */
when ITEM_AMOUNT >= AGG_CAPACITY-CAPACITY then ITEM_AMOUNT - (AGG_CAPACITY-CAPACITY) /* partly allocated */
else 0 end /* not allocated */
as allocated
from agg
order by bag_type, capacity desc;
BAG_ID BAG_TYPE CAPACITY ALLOCATED
------ -------- ---------- ----------
1 A 500 500
2 A 300 300
3 A 100 50
4 B 200 200
5 B 100 100
请注意,如果您想最大程度地减少浪费容量,那么分配的顺序很重要,并且使用不同的顺序找到最佳分配可能很困难。
这应该可以解决问题:
select t1.bag_id
, t1.bag_type
, t1.capacity
, least( t1.capacity -- don't over fill the bag
, greatest( 0 -- don't under fill the bag
, t2.item_amount -- to be allocated
- nvl(sum(t1.capacity) -- less previous allocations
over (partition by t1.bag_type
order by t1.capacity desc
rows between unbounded preceding and 1 preceding)
, 0))) Allocated
from t1
join t2
on t2.item_type = t1.bag_type;
BAG_ID B CAPACITY ALLOCATED
---------- - ---------- ----------
1 A 500 500
2 A 300 300
3 A 100 50
4 B 200 200
5 B 100 100
假设我有 2 tables T1
和 T2
如下
T1
:
bag_id bag_type capacity
------|--------|--------
1 A 500
2 A 300
3 A 100
4 B 200
5 B 100
T2
:
item_type item_amount
---------|-----------
A 850
B 300
tableT1
中的每条记录代表一个包及其容量,这里我有5个包。我想写一个 SQL 将 table T2
中的项目分配到每个相同类型的包中,即结果应该是这样的
bag_id bag_type capacity allocated_amount
------|--------|--------|----------------
1 A 500 500
2 A 300 300
3 A 100 50
4 B 200 200
5 B 100 100
因此,我正在寻找某种聚合函数,我们称它为 allocate()
,它可以生成如上所述的列 allocated_amount
。 我有猜测,如果存在,可能会像这样使用
select
t1.bag_id,
t1.bag_type,
t1.capacity,
allocate(t2.item_amount, t1.capacity)
over (partition by t1.bag_type order by t1.capacity desc) as allocatd_amount
from t1, t2
where t2.item_type = t1.bag_type
我目前的解决方案是使用临时 table 和 PL/SQL 循环进行计算,但我希望我可以用一个简单的 SQL.
来完成您正在查找累计金额。像这样:
select t1.*,
(case when cumecap <= t2.item_amount
then t1.capacity
when cumecap - t1.capacity <= t2.item_amount
then t2.item_amount - (cumecap - t1.capacity)
else 0
end) as allocated_capacity
from (select t1.*,
sum(t1.capacity) over (partition by bag_type order by bag_id) as cumecap
from t1
) t1 join
t2
on t1.bag_type = t2.item_type;
假设按照包容量的降序分配
with agg as (
select bag.BAG_ID, bag.BAG_TYPE, bag.CAPACITY,
SUM(bag.CAPACITY) over (partition by bag.bag_type order by bag.capacity DESC) agg_capacity,
item_amount
from bag, item
where bag.bag_type = item.item_type
)
select
BAG_ID, BAG_TYPE, CAPACITY,
case when ITEM_AMOUNT >= AGG_CAPACITY then CAPACITY /* Full allocated */
when ITEM_AMOUNT >= AGG_CAPACITY-CAPACITY then ITEM_AMOUNT - (AGG_CAPACITY-CAPACITY) /* partly allocated */
else 0 end /* not allocated */
as allocated
from agg
order by bag_type, capacity desc;
BAG_ID BAG_TYPE CAPACITY ALLOCATED
------ -------- ---------- ----------
1 A 500 500
2 A 300 300
3 A 100 50
4 B 200 200
5 B 100 100
请注意,如果您想最大程度地减少浪费容量,那么分配的顺序很重要,并且使用不同的顺序找到最佳分配可能很困难。
这应该可以解决问题:
select t1.bag_id
, t1.bag_type
, t1.capacity
, least( t1.capacity -- don't over fill the bag
, greatest( 0 -- don't under fill the bag
, t2.item_amount -- to be allocated
- nvl(sum(t1.capacity) -- less previous allocations
over (partition by t1.bag_type
order by t1.capacity desc
rows between unbounded preceding and 1 preceding)
, 0))) Allocated
from t1
join t2
on t2.item_type = t1.bag_type;
BAG_ID B CAPACITY ALLOCATED
---------- - ---------- ----------
1 A 500 500
2 A 300 300
3 A 100 50
4 B 200 200
5 B 100 100