Функции 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 

обратите внимание, что порядок распределения важен, если вы хотите минимизировать емкость отходов и найти оптимальное распределение с использованием разных заказов может быть трудно.