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

问题描述

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

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


问题是找到合适尺寸的箱子,让物流企业在运输时节省开支。

我们有 2 张桌子,分别是盒子和产品。

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

产品表还包括产品 ID、尺寸。 Dimensions 与 Box table 具有相同的含义。 “可平铺”是指产品不仅可以平直包装,也可以平铺放置。例如,产品“g”是一个易碎的瓶子,无法将其水平放置在盒子中。因此,这是可放置列中的“n”。

这道题需要查询每个产品ID的大小合适的框。 正确尺寸的盒子意味着产品需要用最小空间的盒子运输。

希望得到您的帮助。谢谢。

盒子:

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 不可用

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

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,h) values ('M',450,350,160);
insert into Boxes (Box_size,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,h,layable) values ('a',25,'y');
insert into products (id,layable) values ('b',160,layable) values ('c',510,layable) values ('d',layable) values ('e',550,layable) values ('f',410,400,430,'n');
insert into products (id,layable) values ('g',240,layable) values ('h',layable) values ('i',310,360,layable) values ('j',500,600,'y');    

commit;

解决方法

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

在所有情况下,如果产品高度 旋转以适合盒子,无论它们是否适合),则匹配是可能的可铺设与否)。

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

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

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,b.d)
                       and greatest(p.h,b.d)
            or
            p.d <= b.h and least   (p.w,p.h) <= least   (b.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 作为“not available”的标记 - 单词“not available”并没有添加比 {{1 的简单使用更有价值的信息}}。

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

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

最后,查询和输出是这样的。请注意,我在 decode() 子句中使用 nvl() 为最后一项生成 select,以防您真的需要它(我怀疑,但这不是我的业务问题。)>

'not available'
,

到目前为止,我可以想出我自己的答案,如下所示,但这似乎每个产品 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.d) <= greatest(b.h,b.w,b.d))
and (least(p.h,p.d) <= least(b.h,b.d))) then b.id
else 'no' end
 else 'not available' end
from products p,boxes b
order by p.id;