我想为订单显示CSV导出,显示每个order_item发货的仓库_id(如果有的话)。
为简洁起见,这是相关的架构:
create table o (id integer);
订单有很多order_items:
create table oi (id integer, o_id integer, sku text, quantity integer);
对于CSV中的每个order_item,我们希望显示出货地点的仓库数据。但是这不存储在order_items中。它存储在货件中。
订单可以分为多个来自不同仓库的货件。
create table s (id integer, o_id integer, warehouse_id integer);
货件也有许多装运项目:
create table si (id integer, s_id integer, oi_id integer, quantity_shipped integer);
我如何为每个order_item提取warehouse_id,因为Warehouse_id在货件上,而不是每个订单都已发货(可能没有货件记录或shipment_items)。
我们正在做这样的事情(简化):
select oi.sku, s.warehouse_id from oi
left join s on s.o_id = oi.o_id;
但是,如果订单有2个订单商品,请让他们称之为sku A和B.然后该订单分为两个货件,其中A从仓库发货,50' 50'然后第二批货从'200'发货。
我们想要的是CSV输出,如:
sku | warehouse_id
-----|--------------
A | 50
B | 200
但我们得到的是某种笛卡尔积:
=================================
Here is the sample data:
select * from o;
id
----
1
(1 row)
select * from oi;
id | o_id | sku | quantity
----+------+-----+----------
1 | 1 | A | 1
2 | 1 | B | 1
(2 rows)
select * from s;
id | o_id | warehouse_id
----+------+--------------
1 | 1 | 50
2 | 1 | 200
(2 rows)
select * from si;
id | s_id | oi_id
----+------+------
1 | 1 | 1
2 | 2 | 2
(2 rows)
select oi.sku, s.warehouse_id from oi left join s on s.o_id = oi.o_id;
sku | warehouse_id
-----+--------------
A | 50
A | 200
B | 50
B | 200
(4 rows)
更新========
每个斯宾塞,为了更清晰,我添加了一个具有不同pk ID的不同示例。以下是2个示例订单。订单2包含项目A,B,C。 A,B从装运200发货,C从装运201装运。订单3有2件E和A. E尚未发货,A从同一仓库装运两次' 700'(就像它在后面订购)。
# select * from o;
id
----
2
3
(2 rows)
# select * from oi;
id | o_id | sku | quantity
-----+------+-----+----------
100 | 2 | A | 1
101 | 2 | B | 1
102 | 2 | C | 1
103 | 3 | E | 1
104 | 3 | A | 2
(5 rows)
# select * from s;
id | o_id | warehouse_id
-----+------+--------------
200 | 2 | 700
201 | 2 | 800
202 | 3 | 700
203 | 3 | 700
(4 rows)
# select * from si;
id | s_id | oi_id
-----+------+-------
300 | 200 | 100
301 | 200 | 101
302 | 201 | 102
303 | 202 | 104
304 | 203 | 104
(5 rows)
我认为这样可行,我使用左连接来保存报表中的order_items,无论订单是否已发货,我使用group by来压缩来自同一仓库的多个货件。我相信这就是我的需要。
# select oi.o_id, oi.id, oi.sku, s.warehouse_id from oi left join si on si.oi_id = oi.id left join s on s.id = si.s_id group by oi.o_id, oi.id, oi.sku, s.warehouse_id order by oi.o_id;
o_id | id | sku | warehouse_id
------+-----+-----+--------------
2 | 102 | C | 800
2 | 101 | B | 700
2 | 100 | A | 700
3 | 104 | A | 700
3 | 103 | E |
(5 rows)
答案 0 :(得分:1)
订购已发货的商品......
SELECT oi.id
, oi.sku
, s.warehouse_id
FROM oi
JOIN si ON si.oi_id = oi.id
JOIN s ON s.id = si.s_id
订购尚未发货的商品,使用反联接排除si中匹配行的行
SELECT oi.id
, oi.sku
, s.warehouse_id
FROM oi
JOIN s ON s.o_id = oi.o_id -- fk to fk shortcut join
-- anti-join
LEFT
JOIN si ON si.oi_id = oi.id
WHERE si.oi_id IS NULL
但这仍将产生(部分)笛卡尔积。我们可以添加GROUP BY子句来折叠行......
GROUP BY si.oi_id
这不会避免产生中间笛卡儿产品;添加GROUP BY子句会折叠该集合。但是,从s
列值中匹配的哪些行将从中返回,这是不确定的。
这两个查询可以与UNION ALL操作结合使用。如果我这样做,我可能会添加一个鉴别器列(每个查询中的一个附加列具有不同的值,这将告诉哪个查询返回了一行。)
此套装可能符合OP问题中列出的规范。但我不认为这真的是需要返回的集合。确定一个物品应该从哪个仓库发货可能涉及多个因素......订购的总数量,每个仓库中可用的数量,可以从一个仓库订购,哪个仓库更靠近交货目的地等等。
我不想让任何人认为此查询确实是一个"修复"对于笛卡尔积问题...这个查询只是隐藏了一个更大的问题。
答案 1 :(得分:0)
我认为你需要si
表:
select oi.sku, s.warehouse_id
from si join
oi
on si.o_id = oi.o_id join
s
on s.s_id = si.s_id;
si
似乎是表之间的正确联结表。我不确定为什么还有另一个不使用它的连接键。