Oracle aggregation function to allocate amount

后端 未结 3 1353
孤独总比滥情好
孤独总比滥情好 2021-02-15 16:29

Suppose I have 2 tables T1 and T2 as follows

T1:

bag_id bag_type capacity
------|--------|--------
  1       A             


        
相关标签:
3条回答
  • 2021-02-15 17:25

    This should do the trick:

    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
    
    0 讨论(0)
  • 2021-02-15 17:28

    You are looking for a cumulative sum. Something like this:

    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;
    
    0 讨论(0)
  • 2021-02-15 17:29

    assuming allocation in the descendent order of bag capacity

    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 
    

    Note that the order of the allocation is important if you want to minimize the waste capacity and finding an optimal allocation using different orders could be hard.

    0 讨论(0)
提交回复
热议问题