Функции Oracle агрегации выделить сумму
Предположим, у меня есть 2 таблицы 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
каждая запись в таблице T1
представляет собой мешок и его мощность, вот у меня есть 5 мешков. Я хочу написать SQL, который выделяет элементы в таблице 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
мое текущее решение-использовать временную таблицу и цикл PL/SQL для расчета, но я надеюсь, что смогу сделать это с помощью одного простого SQL.
3 ответов
вы ищете совокупную сумму. Что-то вроде этого:--2-->
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;
это должно сделать трюк:
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
предполагая выделение в порядке убывания емкости мешка
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
обратите внимание, что порядок распределения важен, если вы хотите минимизировать емкость отходов и найти оптимальное распределение с использованием разных заказов может быть трудно.