在为一家电子商务商店实施仓库管理系统时,我正在尝试为仓库工人创建一个拣配清单,他们将绕着仓库从不同货架的订单中拣选产品。
一种产品可以位于不同的货架上,并且在每个货架上可以有许多相同类型的产品。
如果同一订单中有许多相同的产品,则有时拣选人员必须从多个货架中进行拣选才能将所有物品都放入一个订单中。
为使事情变得更加棘手,有时产品也将售罄。
我的数据模型如下所示(简化):
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中执行此操作。
感谢您的帮助!
答案 0 :(得分: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
;
这是个主意:
product_on_shelf
,该表与warehouse_placement
相同,不同之处在于行重复了n次,n是货架上产品的数量。order_among_product
中的每一行分配一个数字product_on_shelf
,以便货架上的每个对象都知道其在相同产品中的顺序。order_among_product
中的每一行分配一个对称数字order_product
。order_product
中的每一行,我们尝试在货架上找到具有相同order_among_product
的产品。如果找不到任何产品,则意味着我们已经用尽了所有架子上的产品。 注释#1 :将产品下架是同时进行的操作。您应该确保在应用程序端或数据库端通过智能锁,可以将货架上的任何产品归于一个订单。在应用程序端处理product_order
的每一行可能是处理并发的最佳选择。
注释#2 :为清楚起见,我使用CTE编写了此查询。为了提高性能,请考虑改为使用子查询。确保运行EXPLAIN ANALYZE