如何为每种产品找到合适尺寸的包装盒?

How can I find the right size box for each product?

很抱歉重新上传这个问题,但我真的很想知道答案。

请允许我再次提出这个问题,希望您的支持。


问题是找到合适尺寸的盒子,让物流商家在发货时省钱。

我们有 2 个 table 是盒子和产品。

Boxes table 包含每个盒子的每个 ID 和尺寸。 'w' 表示宽度,'d' 表示深度,'h' 表示高度。为方便起见,请假设我们只有 3 盒样品。

产品 table 还包括产品 ID、尺寸。尺寸与框 table 的含义相同。 'layable'表示产品不仅可以直立包装,还可以平放包装。例如产品 'g' 是一个易碎的瓶子,不能水平放置在盒子里。因此,这是可放置列中的 'n'。

这道题需要查询每一个商品ID,箱子大小合适。 正确尺寸的盒子意味着产品需要使用最少 space.

的盒子运送

希望您的帮助。谢谢

盒数:

BOX_SIZE W D H
S 353 250 25
M 450 350 160
L 610 460 460

产品:

ID W D H LAYABLE
a 350 250 25 y
b 450 250 160 y
c 510 450 450 y
d 350 250 25 y
e 550 350 160 y
f 410 400 430 n
g 350 240 25 n
h 450 350 160 n
i 310 360 430 n
j 500 500 600 y

预期输出:

ID BOX_SIZE
a S
b M
... ....
... ....
... ....
g S
h M
i L
j not available

用于创建和填充 table 进行测试的语句:

create table boxes
    ( box_size char(1) primary key
    , w        number  not null
    , d        number  not null
    , h        number  not null
    )
;

insert into boxes (box_size, w, d, h) values ('S', 353, 250,  25);
insert into boxes (box_size, w, d, h) values ('M', 450, 350, 160);
insert into boxes (box_size, w, d, h) values ('L', 610, 460, 460);

create table products
    ( id      varchar2(10) primary key
    , w       number       not null
    , d       number       not null
    , h       number       not null
    , layable char(1)      check(layable in ('y', 'n'))
    )
;

insert into products (id, w, d, h, layable) values ('a', 350, 250,  25, 'y');
insert into products (id, w, d, h, layable) values ('b', 450, 250, 160, 'y');
insert into products (id, w, d, h, layable) values ('c', 510, 450, 450, 'y');
insert into products (id, w, d, h, layable) values ('d', 350, 250,  25, 'y');
insert into products (id, w, d, h, layable) values ('e', 550, 350, 160, 'y');
insert into products (id, w, d, h, layable) values ('f', 410, 400, 430, 'n');
insert into products (id, w, d, h, layable) values ('g', 350, 240,  25, 'n');
insert into products (id, w, d, h, layable) values ('h', 450, 350, 160, 'n');
insert into products (id, w, d, h, layable) values ('i', 310, 360, 430, 'n');
insert into products (id, w, d, h, layable) values ('j', 500, 500, 600, 'y');    

commit;

到目前为止,我可以得出自己的答案,如下所示,但这似乎每个产品 ID 都有三行。因此,这需要过滤到每个查询的最小框。我厌倦了使用 min(function) 但这会导致错误。

select p.id, p.h, p.w, p.d, p.layable, case
when p.layable = 'n' then case 
 when p.h <= b.h and 
((greatest(p.w, p.d ) <= greatest(b.w, b.d)) 
and (least(p.w, p.d) <= least(b.w, b.d))) then b.id
else 'no' end
when p.layable = 'y' then case 
when (p.h + p.w + p.d) <= (b.h + b.w + b.d) and 
((greatest(p.h, p.w, p.d) <= greatest(b.h, b.w, b.d))
and (least(p.h, p.w, p.d) <= least(b.h, b.w, b.d))) then b.id
else 'no' end
 else 'not available' end
from products p, boxes b
order by p.id;

关键当然是两个table之间的连接。我先单独展示它,而不是完整的查询,以帮助理解。对于每个项目,我们找到可以容纳该项目的所有盒子尺寸。

在所有情况下,如果产品高度 <= 盒子高度,并且其他两个尺寸适合,在任一排列中都可以匹配(产品始终可以 旋转 以适合盒子,无论它们是否可放置)。

仅对于可放置的产品,我们可以在所有三个维度上旋转产品以将其放入盒子中。这意味着,仅对于可放置产品,我们可以将产品宽度或深度与盒子高度进行比较,并将产品的剩余两个尺寸与盒子宽度和深度进行比较。

一旦我们理解了我刚才说的内容(就像我们在没有计算机的情况下,只用铅笔在纸上做的那样),翻译成代码几乎是自动的:

select p.id, b.box_size
from   products p left outer join boxes b
       on
            p.h <= b.h and least   (p.w, p.d) <= least   (b.w, b.d)
                       and greatest(p.w, p.d) <= greatest(b.w, b.d)
       or
       p.layable = 'y'
          and
          ( p.w <= b.h and least   (p.h, p.d) <= least   (b.w, b.d)
                       and greatest(p.h, p.d) <= greatest(b.w, b.d)
            or
            p.d <= b.h and least   (p.w, p.h) <= least   (b.w, b.d)
                       and greatest(p.w, p.h) <= greatest(b.w, b.d)
          )
;

输出:

ID  BOX_SIZE
--- --------
a   S       
a   M       
a   L       
b   M       
b   L       
c   L       
d   S       
d   M       
d   L       
e   L       
f   L       
g   S       
g   M       
g   L       
h   M       
h   L       
i   L       
j      

对于每个产品,我们都找到了所有合适的尺寸。

注意查询中的外连接,以包含不适合任何框尺寸的产品;出现在输出末尾的产品 j 就是这种情况。请注意,我使用 null 作为“不可用”的标记 - “不可用”一词在null.

的简单使用

下一步是简单的聚合 - 对于每个产品,找到可行的最小尺寸。最好的工具是 FIRST 聚合函数(如下所用)。我们必须按盒子尺寸订购;由于大小是 S、M、L(只是偶然按字母顺序倒序排列),我使用 decode() 函数将 1 分配给 S,2 分配给 M,3 分配给 L。聚合查询找到“第一个“适用于每个产品的尺寸。

这里重要的是查询可以很容易地推广到任意数量的可能的“框大小”——即使不是所有三个维度都按递增顺序排列。 (你也可以有只有一个尺寸非常大而其他尺寸很小的盒子,等等)。您可以按箱量订购,也可以在箱子table中存储一个偏好顺序,相当于我在查询中使用decode()函数所做的.

最终,查询和输出如下所示。请注意,我在 select 子句中使用 nvl() 为最后一项生成 'not available' ,以防万一您确实需要它(我对此表示怀疑,但这不是我的业务问题。)

select p.id, 
       nvl(  min(b.box_size) keep (dense_rank first 
             order by decode(b.box_size, 'S', 1, 'M', 2, 'L', 3))
          , 'not available') as box_size
from   products p left outer join boxes b
       on
            p.h <= b.h and least   (p.w, p.d) <= least   (b.w, b.d)
                       and greatest(p.w, p.d) <= greatest(b.w, b.d)
       or
       p.layable = 'y'
          and
          ( p.w <= b.h and least   (p.h, p.d) <= least   (b.w, b.d)
                       and greatest(p.h, p.d) <= greatest(b.w, b.d)
            or
            p.d <= b.h and least   (p.w, p.h) <= least   (b.w, b.d)
                       and greatest(p.w, p.h) <= greatest(b.w, b.d)
          )
group  by p.id
;

ID  BOX_SIZE
--- --------
a   S       
b   M       
c   L       
d   S       
e   L       
f   L       
g   S       
h   M       
i   L       
j   not available