暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 桶之间的随机数量

ASKTOM 2021-04-28
235

问题描述

嗨,汤姆,

我被赋予了八个桶的 “当前” 项目分配,我想通过尽可能多地填充桶A,然后是桶B,然后是桶C (如 “优先级” 所示) 来提高效率,通过从存储桶H中获取尽可能多的P1项目并将它们重新分配给存储桶A (尽可能多),然后再分配给存储桶B等,从而在存储桶之间移动项目,直到您分配了所有项目。然后,您选择下一个最低优先级的存储桶并重复。在体积表中定义了要填充的P1和P2的数量,即每个A,b-h可以具有样本数据中P1和P2的8和7的倍数。

我还想包括四舍五入和四舍五入逻辑,以在一个桶中的数量太大的情况下几乎将数量分配到整个桶中。

项目P1和P2是完全独立的,一个的结果不应该影响另一个。高度,重量和宽度在这里无关紧要,因此不会出现在任何样本数据中。

下面的内容我已经开始了,但是无法使四舍五入的案例起作用。此外,在将数量从一个桶移动到两个或多个桶或从两个桶移出到一个桶的情况下,我们可以显示一个逗号分隔的行而不是多个逐步行吗?

在一行数量过多的情况下,我们是否可以实现向上舍入和向下舍入逻辑,以将数量平均分配给桶中值表的数量的倍数,例如如果我们将数量更新为P1部分的桶H中的72个,当前结果给出了H桶的五行。我们可以用十六个桶将A-H桶旋转,然后将H桶中的其余桶旋转吗?

专家解答

因此,您想在桶之间尽可能均匀地分配物品体积的倍数的数量吗?

要查看要分配给每个存储桶的数量,可以使用以下公式对该单元进行四舍五入:

round ( avg ( item quantities ) / volume ) * volume


这种情况存在一些挑战。

首先,这是装箱问题的一种形式。一般来说,这些是hard问题,这意味着没有已知的解决方案可以保证既快速又正确。

接下来,您需要跟踪从其他存储桶分配了多少。这意味着使用递归was或model子句。这些可能很难编写和理解。两者都可能需要很长时间来处理大型数据集。

因此,尽管我通常提倡SQL方法,但这是一种情况,其中过程PL/SQL可能既易于编写又执行得更快。

最后,我知道你在12.1,但是21c中的新循环结构使代码更加紧凑。所以我无法抗拒使用它们;) 在以下位置阅读更多关于这些的信息:

https://blogs.oracle.com/plsql-and-ebr/better-loops-and-qualified-expressions-array-constructors-in-plsql

下面是我使用的算法的草图:

-获取一个项目的所有桶,使用上面的公式计算目标数量
-按优先级顺序遍历存储桶,跳过任何已经足够的存储桶
-有一个内部循环,通过桶向后工作
-如果内桶有,则将金额分配给外桶
-优先级较低
-超额数量

create table priorities (bucket, priority) as 
  select 'A', 1 from dual union all 
  select 'B', 2 from dual union all 
  select 'C', 3 from dual union all 
  select 'D', 4 from dual union all 
  select 'E', 5 from dual union all 
  select 'F', 6 from dual union all 
  select 'G', 7 from dual union all 
  select 'H', 8 from dual ;

create table volumes (item, quantity) as 
  select 'P1', 8 from dual union all 
  select 'P2', 7 from dual ;

create table data (bucket, item, present_qty) as 
  select 'A', 'P1', 6 from dual union all 
  select 'B', 'P1', 9 from dual union all 
  select 'C', 'P1', 8 from dual union all 
  select 'D', 'P1', 1 from dual union all 
  select 'F', 'P1', 0 from dual union all 
  select 'G', 'P1', 8 from dual union all 
  select 'H', 'P1', 72 from dual union all 
  select 'A', 'P2', 3 from dual union all 
  select 'B', 'P2', 5 from dual union all 
  select 'C', 'P2', 7 from dual union all 
  select 'D', 'P2', 9 from dual union all 
  select 'E', 'P2', 1 from dual union all 
  select 'F', 'P2', 4 from dual union all 
  select 'H', 'P2', 4 from dual ;

create or replace procedure fill_buckets ( fill_item varchar2 ) is
  cursor bucket_cur is
    select bucket, present_qty, 
           round ( 
             avg ( present_qty ) over ( 
               partition by item
             ) / quantity 
           ) * quantity as quantity, 
           null source
    from   priorities
    join   data
    using  ( bucket )
    join   volumes 
    using  ( item )
    where  item = fill_item
    order  by priority;
  
  type bucket_arr 
    is table of bucket_cur%rowtype
    index by pls_integer;
    
  bucket_recs bucket_arr;
  num_buckets pls_integer;
  excess      pls_integer;
begin
  open bucket_cur;
  fetch bucket_cur
  bulk collect into bucket_recs;
  close bucket_cur;
  
  num_buckets := bucket_recs.count;
  
  for i, v in pairs of bucket_recs 
    /* Only consider buckets under capacity */
    when bucket_recs ( i ).present_qty < bucket_recs ( i ).quantity
  loop

    for j in reverse 1 .. num_buckets 
      /* Only attempt different buckets 
         with lower priority or excess quantity */
      when i <> j and ( 
        i < j or 
        bucket_recs ( j ).present_qty > bucket_recs ( i ).quantity 
      )
    loop
      
      if i < j then
        excess := least (
          bucket_recs ( i ).quantity - bucket_recs ( i ).present_qty,
          bucket_recs ( j ).present_qty
        );
      else
        excess := least (
          bucket_recs ( j ).present_qty - bucket_recs ( j ).quantity,
          bucket_recs ( i ).quantity - bucket_recs ( i ).present_qty
        );      
      end if;

      continue when excess <= 0;
           
      bucket_recs (i).present_qty := bucket_recs (i).present_qty + excess;
      bucket_recs (j).present_qty := bucket_recs (j).present_qty - excess;
      bucket_recs (i).source := bucket_recs (i).source || ',' || bucket_recs (j).bucket || '-' || excess;
      
    end loop;
  end loop;
  
  for i, v in pairs of bucket_recs loop
    dbms_output.put_line ( 
      v.bucket || '-' || v.present_qty || ' taken from ' || v.source 
    );
  end loop;
end;
/

exec fill_buckets ( 'P1' );

A-16 taken from ,H-10
B-16 taken from ,H-7
C-16 taken from ,H-8
D-16 taken from ,H-15
F-16 taken from ,H-16
G-16 taken from ,H-8
H-8 taken from

exec fill_buckets ( 'P2' );

A-7 taken from ,H-4
B-7 taken from ,F-2
C-7 taken from 
D-7 taken from 
E-5 taken from ,F-2,D-2
F-0 taken from 
H-0 taken from

文章转载自ASKTOM,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论