问题描述
很抱歉重新上传这个问题,但我真的很想要答案。
请允许我再次提出这个问题,希望得到您的支持。
问题是找到合适尺寸的箱子,让物流企业在运输时节省开支。
我们有 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;