【问题标题】:How can I find the right size box for each product?如何为每种产品找到合适尺寸的盒子?
【发布时间】:2021-02-13 09:07:00
【问题描述】:

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

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


问题是找到合适尺寸的盒子,让物流业务在运输时节省资金。

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

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

产品表还包括产品 ID、尺寸。尺寸与盒子表的含义相同。 'layable' 是指产品不仅可以直接包装,还可以包装。例如,产品“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 not available

创建和填充测试表的语句:

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;

【问题讨论】:

  • 有趣的问题!我想我了解“可铺设与不可铺设”的业务;对于不可铺设的物品,宽度和深度可以互换,但高度不能互换,而对于可铺设的物品,所有三个尺寸都是可以互换的。然后,您谈论“最小空间”;那是怎么定义的?我猜至少是 VOLUME,但我在您的查询中没有看到体积计算。
  • 我编辑了您的问题,添加了create tableinsert 语句以重新创建测试数据。像您发布的图像看起来不错,但不是很有帮助;请养成以我添加的格式提供数据的习惯。 (如果除了您还添加格式中的表格,那可能是最好的选择。)还要注意我将列名 size 更改为 box_size ,因为 size 是 Oracle 中的保留关键字;它不应该用作表名或列名。
  • 回到“最小空间”——我想我明白了。在您的情况下,盒子尺寸 S、M、L 的所有尺寸都按严格递增的顺序排列,因此没有歧义。尽可能使用 S,如果没有,则尽可能使用 M,或者如果这也不可能,使用 L。或者报告“不可用”。
  • 再补充一点 - 我进一步编辑了您的问题,以添加一种不适合任何盒子的产品。您的测试数据应始终包含此类特殊情况。 (您甚至提到了这种可能性,只是您的示例中没有包含示例。)
  • 感谢您提供详细的 cmets。一切看起来清晰合理。我应该用测试数据制作create table。通过“最小空间”,您可以很好地理解我试图解释的内容。谢谢。

标签: sql oracle logistics


【解决方案1】:

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

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

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

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

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。聚合查询找到“第一个”适用于每种产品的尺寸。

这里重要的是,查询可以很容易地推广到任意数量的可能“盒子大小”——即使不是所有三个维度都按递增顺序排列。 (您也可以拥有只有一个尺寸非常大而其他尺寸很小的盒子,等等)。您可以按盒子体积排序,也可以在盒子表中存储优先顺序,这与我在查询中使用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   

【讨论】:

  • 嗨@Mathguy,我非常感谢您在这里的辛勤工作。你的代码、输出和你对我艰难的解释的深刻理解给我留下了深刻的印象。你所有的解释看起来都很容易理解和合乎逻辑。而解码和NVL等代码可以在我的实际业务问题中采用,因为我只是将数据放在简单的方式,但实际上它应该进一步开发。因此,我必须说,您的理解和解释太棒了。再次感谢您!
【解决方案2】:

到目前为止,我可以提出自己的答案,如下所示,但这似乎每个产品 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;

【讨论】:

  • layable案例中的条件不正确。满足最小和最大维度的条件,以及维度的总和,并不能保证剩余维度的不等式。这是一个简单的反例:项目尺寸为 3、7 和 10,盒子尺寸为 4、6 和 20。3
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 2012-12-08
  • 2016-05-16
  • 2014-05-27
  • 2013-08-18
  • 1970-01-01
相关资源
最近更新 更多