Oracle PL/sql : 计算所有可能数字组合的总和

Oracle PL/sql : Calculate sum of all possible number combinations

甲骨文数据库

假设我有 3 个箱子,里面装有不同数量的物品(箱子数量是固定的)

盒子编号和数量如下

B101 5
B102 5
B103 4

有一个容器,里面有一定数量的物品

现有数量 - 2

容器容量- 15

现在我想要 box1,box2,box3 现有数量的所有可能组合的总和。

我会select只有总和 < 容量最适合的组合

所有组合都必须有现有数量,因为我们不能忽略它

本案例的最终结果

盒子 1 + 盒子 2 + 现有数量 .5+5+2 适合容量 15 .

需要一个 PL/SQL 块来执行相同的 activity

我将在 table 条记录(用户定义)

中获取箱子 ID 和箱子数量

可能有更简单的方法,但我会使用递归 CTE。这是一个简单的 SQL 示例,带有额外的示例行:

create table boxes (id varchar2(4), qty number);

insert into boxes values ('B101',5);
insert into boxes values ('B102',5);
insert into boxes values ('B103',4);
insert into boxes values ('B104',9);
insert into boxes values ('B105',11);
insert into boxes values ('B106',2);
insert into boxes values ('B107',1);

with c (r, id, qty, lvl) as (
    -- anchor query
    select id as r, id, qty, 1 as lvl
    from boxes
    where qty + 2 < 15
    union all
    -- recursive query
    select c.r || ',' || b.id, b.id, b.qty+c.qty, c.lvl+1
    from boxes b
    join c on c.id < b.id
    where b.qty + c.qty + 2 < 15
    )
select r, lvl, qty 
from c
order by qty desc, lvl asc
;

这将显示所有组合,最适合的在顶部。我在级别上添加了次要排序,假设在平局的情况下,您希望每个容器的盒子数量最少。但您可能更喜欢每个容器的最大盒数。

我还使用了 join on c.id < b.id 而不是交叉连接,因为我认为你并不是真的想要所有组合,你想要所有 UNIQUE 组合,所以它更像是一个树搜索。

作为 PL/SQL 函数的示例:

create or replace function fit_boxes(existing_qty in number, capacity in number)
return varchar2
is
    box_list varchar2(4000);
begin

    with c (r, id, qty, lvl) as (
        select id as r, id, qty, 1 as lvl
        from boxes
        where qty + existing_qty < capacity
        union all
        select c.r || ',' || b.id, b.id, b.qty+c.qty, c.lvl+1
        from boxes b
        join c on c.id < b.id
        where b.qty + c.qty + existing_qty < capacity
        )
    select r into box_list
    from c
    order by qty desc, lvl asc
    fetch first 1 row only
    ;

    return box_list;

exception when NO_DATA_FOUND then
  return 'No boxes fit'
end;
/

select fit_boxes(2,15) from dual;

最后,我猜到你想要sum <= capacity,但你的问题肯定是“sum < capacity”,所以我就是这样写的。只需使用您的数据对其进行测试,并确保它按预期工作。

编辑:当然,为了解释查询逻辑 - 对于 递归 CTE,您从锚查询开始并将其合并到递归查询(它不断地从CTE 本身)。

对于锚点,我们首先选择可以放入容器中的所有单个框(其中 qty + 2 < 15)。在我们的示例中,它们都适合,所以我们有 7 行,lvl 为 1。

对于递归部分,容器 c 中已经有 1 个或多个框,我们想看看 b 中剩余的哪些框适合。所以我们加入他们,使用 c.id < b.id 来确保我们只查看 b 中的框,而 c 中还没有这些框。一旦我们查看了所有框,连接将 return 0 行并且递归将停止。

对于 CTE 中的 4 列 - r 显示到目前为止我们添加到容器中的所有框,id 显示最近添加的框的 ID(所以很重要我们可以跟踪我们考虑过哪些盒子),qty 总结容器中当前所有盒子的大小,lvl 显示容器中有多少个盒子。