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
显示容器中有多少个盒子。
甲骨文数据库
假设我有 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
显示容器中有多少个盒子。