【问题标题】:Order picking in warehouse仓库拣货
【发布时间】:2018-09-09 18:40:27
【问题描述】:

在为电子商务商店实施仓库管理系统时,我正在尝试为仓库工作人员创建一个拣货清单,他们将在仓库中四处走动,从不同货架上挑选订单中的产品。

一种产品可以放在不同的货架上,每个货架上可以有许多相同类型的产品。

如果一个订单中有许多相同的产品,有时拣货员必须从多个货架中挑选才能获得订单中的所有商品。

为了进一步使事情变得更棘手,有时产品也会缺货。

我的数据模型如下所示(简化):

CREATE TABLE order_product (
    id SERIAL PRIMARY KEY,
    product_id integer,
    order_id text
);

INSERT INTO "public"."order_product"("id","product_id","order_id")
VALUES
(1,1,'order1'),
(2,1,'order1'),
(3,1,'order1'),
(4,2,'order1'),
(5,2,'order2'),
(6,2,'order2');

CREATE TABLE warehouse_placement (
    id SERIAL PRIMARY KEY,
    product_id integer,
    shelf text,
    quantity integer
);

INSERT INTO "public"."warehouse_placement"("id","product_id","shelf","quantity")
VALUES
(1,1,E'A',2),
(2,2,E'B',2),
(3,1,E'C',2);

是否可以在 postgres 中生成如下指令的选择列表:

order_id product_id shelf quantity_left_on_shelf
order1   1          A     1
order1   1          A     0
order1   2          B     1
order1   1          C     1
order2   2          B     0
order2   2         NONE   null     

我目前在应用程序代码中执行此操作,但感觉很笨拙,不知何故我觉得应该有一种方法可以直接在 SQL 中执行此操作。

感谢您的帮助!

【问题讨论】:

    标签: postgresql e-commerce


    【解决方案1】:

    我们开始吧:

    WITH product_on_shelf AS (
        SELECT warehouse_placement.*, 
               generate_series(1, quantity) AS order_on_shelf,
               quantity - generate_series(1, quantity) AS quantity_left_on_shelf
        FROM warehouse_placement
    )
    , product_on_shelf_with_product_order AS (
        SELECT *,
               ROW_NUMBER() OVER (
                   PARTITION BY product_id 
                   ORDER BY quantity, shelf, order_on_shelf
               ) AS order_among_product
        FROM product_on_shelf
    )
    , order_product_with_order_among_product AS (
        SELECT *,
               ROW_NUMBER() OVER (
                   PARTITION BY product_id 
                   ORDER BY id
               ) AS order_among_product
        FROM order_product
    )
    SELECT order_product_with_order_among_product.id,
           order_product_with_order_among_product.order_id,
           order_product_with_order_among_product.product_id,
           product_on_shelf_with_product_order.shelf,
           product_on_shelf_with_product_order.quantity_left_on_shelf
    FROM order_product_with_order_among_product
    LEFT JOIN product_on_shelf_with_product_order
        ON order_product_with_order_among_product.product_id = product_on_shelf_with_product_order.product_id
        AND order_product_with_order_among_product.order_among_product = product_on_shelf_with_product_order.order_among_product
    ORDER BY order_product_with_order_among_product.id
    ;
    

    这就是想法

    1. 我们创建一个临时表product_on_shelf,与warehouse_placement相同,只是行重复n次,n是货架上的产品数量。
    2. 我们为product_on_shelf 中的每一行分配一个编号order_among_product,以便货架上的每个物品都知道其在相同产品中的顺序。
    3. 我们为order_product 中的每一行分配一个对称数order_among_product
    4. 对于order_product 中的每一行,我们尝试在货架上查找具有相同order_among_product 的产品。如果我们找不到任何产品,则意味着我们已经用尽了任何货架上的产品。

    旁注 #1:从货架上挑选产品是一项并行操作。您应该通过智能锁在应用程序端或数据库端确保货架上的任何产品都可以归于一个订单。在应用程序端处理product_order 的每一行可能是处理并发的最佳选择。

    旁注#2:为了清楚起见,我使用 CTE 编写了这个查询。为了提高性能,请考虑改用子查询。确保运行EXPLAIN ANALYZE

    【讨论】:

    • 很好的解决方案,很好的解释!
    • 这完美地回答了我的问题,并且是解决问题的一种非常好的方法。感谢一百万马修!
    • 回复。同时,一开始只有一个打包机,所以这不是问题。一旦我们需要多个拣货员同时工作,我打算锁定订单,这样每个拣货员就可以排他地同时拣选 10 个订单。
    猜你喜欢
    • 2021-04-17
    • 2021-04-12
    • 2020-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多