我在sql中遇到问题,我需要从事务列表中生成一个装箱单。
交易存储在包含以下内容的表格中:
每个事务可以有多个项目(巧合的是多个行具有相同的事务ID)。然后每个项目的数量从1到N.
业务要求我们创建一个装箱单,其中装箱单中的每个项目都包含方框中每个项目的计数。
每个盒子只能包含160个物品(它们的大小/重量都相同)。根据订单的总数,我们需要将项目拆分到不同的框中(有时甚至将单个项目的集合拆分为两个框)
因此,挑战在于采用该数据模式并提出结果集,其中包括每个项目中每个项目的数量。
我目前正以一些不那么漂亮的方式强行推动这一点,并想知道是否有人有一个我忽略的优雅/简单的解决方案。
我们确实需要隔离每个项目中每个项目的数量...例如:
订单1:
理想情况下,查询将足够聪明以将所有C放在一起,但此时 - 我们并不太关心它。
答案 0 :(得分:3)
答案 1 :(得分:2)
像
这样的东西SELECT SUM([Item quantity]) as totalItems
, SUM([Item quantity]) / 160 as totalBoxes
, MOD(SUM([Item Quantity), 160) amountInLastBox
FROM [Transactions]
GROUP BY [Transaction Id]
让我知道您正在寻找的结果集中的哪些字段,我可以想出一个更好的字段
答案 2 :(得分:1)
我正在寻找类似的东西,我所能做到的只是将行扩展到事务中的项目计数,并将它们分组到容器中。虽然不是很优雅..而且,因为字符串聚合在SQL Server中仍然非常麻烦(Oracle,我想念你!),我不得不留下最后一部分。我的意思是把计数放在一行......
交易表示例:
INSERT INTO transactions
(trans_id, item, cnt) VALUES
('1','A','50'),
('2','A','140'),
('3','B','100'),
('4','C','80');
GO
创建一个虚拟序列表,其中包含1到1000之间的数字(我假设单个事务中项目允许的最大数量为1000):
CREATE TABLE numseq (n INT NOT NULL IDENTITY) ;
GO
INSERT numseq DEFAULT VALUES ;
WHILE SCOPE_IDENTITY() < 1000 INSERT numseq DEFAULT VALUES ;
GO
现在我们可以从事务表中生成一个临时表,其中每个事务和项在子查询中存在“cnt”次,然后使用除法给bin分配数字,并按bin分组号:
SELECT bin_nr, item, count(*) count_in_bin
INTO result
FROM (
SELECT t.item, ((row_number() over (order by t.item, s.n) - 1) / 160) + 1 as bin_nr
FROM transactions t
INNER JOIN numseq s
ON t.cnt >= s.n -- join conditionally to repeat transaction rows "cnt" times
) a
GROUP BY bin_id, item
ORDER BY bin_id, item
GO
结果是:
bin_id item count_in_bin
1 A 160
2 A 30
2 B 100
2 C 30
3 C 50
在Oracle中,最后一步就是这样简单:
SELECT bin_id, WM_CONCAT(CONCAT(item,'(',count_in_bin,')')) contents
FROM result
GROUP BY bin_id
答案 3 :(得分:1)
它使用CTE
答案 4 :(得分:0)
这不是最漂亮的答案,但我使用类似的方法通过订单流程跟踪库存商品,这很容易理解,并可能导致您开发出比我更好的方法。
我会创建一个名为“PackedItem”的表或类似的东西。列将是:
packed_item_id (int) - Primary Key, Identity column
trans_id (int)
item_id (int)
box_number (int)
此表中的每条记录代表您将发运的1个物理单位。
让我们说有人在事务4中添加第20行第20项,我会在PackedItem表中添加20条记录,所有记录都包含事务ID,Item ID和NULL框号。如果更新了一行,则需要在PackedItem表中添加或删除记录,以便始终保持1:1的相关性。
到货的时候,你可以简单地
SELECT TOP 160 FROM PackedItem WHERE trans_id = 4 AND box_number IS NULL
并将这些记录的box_number
设置为下一个可用的框号,直到box_number
为NULL时没有记录。这可以在WHILE循环中使用一个相当复杂的UPDATE语句 - 我没有时间完全构造。
现在,您可以通过查询此表轻松获得所需的装箱单:
SELECT box_number, item_id, COUNT(*) AS Qty
FROM PackedItem
WHERE trans_id = 4
GROUP BY box_number, item_id
优点 - 易于理解,易于实施。 陷阱 - 如果表与事务中的行不同步,最终结果可能是错误的;该表将在其中获得许多记录,并将为服务器提供额外的工作。需要对每个ID字段进行索引以保持良好的性能。