簡體   English   中英

Oracle PL/sql:計算所有可能數字組合的總和

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

Oracle數據庫

假設我有 3 個盒子,里面有不同數量的物品(盒子的數量是固定的)

盒子編號和數量如下

B101 5
B102 5
B103 4

有一個容器,里面有一些物品

現有數量 - 2

容器容量 - 15

現在我想要box1,box2,box3,現有數量的所有可能組合的總和。

我將 select 只有總和 < 容量最適合的組合

所有組合都必須具有現有數量,因為我們不能忽略它

本案例的最終結果

框 1 + 框 2 + 現有數量 5+5+2,可容納 15 人。

需要一個 PL/SQL 塊來執行相同的活動

我將在記錄表中獲取盒子 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而不是交叉連接,因為我認為你並不是真的想要所有組合,你想要所有唯一的組合,所以它更像是一個樹搜索。

以及作為 PL/SQL function 的示例:

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中。 一旦我們查看了所有的框,連接將返回 0 行並且遞歸將停止。

對於 CTE 中的 4 列 - r顯示了到目前為止我們添加到容器中的所有框, id顯示了最近添加的框的 id(很重要,因此我們可以跟蹤我們考慮過的框), qty總結了容器中當前所有盒子的大小, lvl顯示了容器中有多少盒子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM