edit:当用户Larna请求为子查询表创建/插入时,我也添加了这些。
以下查询返回:
DocNum ItemCode Planned Qty WhsCode BinCode QuantityToPick 901903 A00001 12.000000 98 98-A001 7.000000 901903 A00001 12.000000 98 98-A002 5.000000 --sum of 5 and 7 makes 12 901904 A00001 17.000000 98 98-A001 7.000000 901904 A00001 17.000000 98 98-A002 6.000000 901904 A00001 17.000000 98 98-A003 4.000000 --sum of 7,6 and 4 makes 17 But I want to have this result: DocNum ItemCode Planned Qty WhsCode BinCode QuantityToPick 901903 A00001 12.000000 98 98-A001 7.000000 901903 A00001 12.000000 98 98-A002 5.000000 --sum of 5 and 7 makes 12 -- continue from bin code 98A002 for the new docnum as we had 5 out of 6 where consumed 901904 A00001 17.000000 98 98-A002 1.000000 901904 A00001 17.000000 98 98-A003 12.000000 901904 A00001 17.000000 98 98-A004 4.000000 --sum of 1,12 and 4 makes 17
因此,基本上,我想继续使用第一个DocNum,ItemCode,Quantity eat
部分地-- Create Tables for Subquerys + insert relevant data
CREATE TABLE [dbo].[WOR1](-- Removed the unimportant columns
[DocEntry] [int] NOT NULL,
[LineNum] [int] NOT NULL,
[ItemCode] [nvarchar](50) NULL,
[PlannedQty] [numeric](19, 6) NULL,
[IssuedQty] [numeric](19, 6) NULL,
[wareHouse] [nvarchar](8) NULL
)
INSERT INTO [dbo].[WOR1]
VALUES(154 ,0 ,'A00001' ,12.000000 ,0.000000, '01')
,(154 ,1 ,'P10001' ,12.000000 ,0.000000, '01')
,(154 ,2 ,'L10001' ,12.000000 ,0.000000, '01')
,(155 ,0 ,'A00001' ,17.000000 ,0.000000, '01')
,(155 ,1 ,'P10001' ,17.000000 ,0.000000, '01')
,(155 ,2 ,'L10001' ,17.000000 ,0.000000, '01')
CREATE TABLE [dbo].[OWOR](-- Removed the unimportant columns
[DocEntry] [int] NOT NULL,
[DocNum] [int] NOT NULL,
[Status] [char](1) NULL
)
INSERT INTO [dbo].[OWOR]
VALUES( 154, 901903, 'R')
,( 155, 901904, 'R')
CREATE TABLE [dbo].[OIBQ](-- Removed the unimportant columns
[ItemCode] [nvarchar](50) NOT NULL,
[BinAbs] [int] NOT NULL,
[OnHandQty] [numeric](19, 6) NULL,
[WhsCode] [nvarchar](8) NULL
)
INSERT INTO [dbo].[OIBQ]
VALUES('A00001', 7, 15.000000, '98')
,('A00001', 2, 7.000000, '98')
,('A00001', 3, 6.000000, '98')
,('A00001', 4, 12.000000, '98')
CREATE TABLE [dbo].[OBIN](-- Removed the unimportant columns
[AbsEntry] [int] NOT NULL,
[BinCode] [nvarchar](228) NOT NULL,
[WhsCode] [nvarchar](8) NULL
)
INSERT INTO [dbo].[OBIN]
VALUES(1, '98-SYSTEM-BIN-LOCATION', '98')
,(2, '98-A001', '98')
,(3, '98-A002', '98')
,(4, '98-A003', '98')
,(5, '98-A004', '98')
,(6, '98-A005', '98')
,(7, '98-A006', '98')
之后的中断处
并继续使用第二个DocNum,ItemCode,Quantity来“吃掉”第二个垃圾箱的剩余数量,然后剩余的剩余垃圾箱直到我达到0
但是我对如何执行此操作有些困惑。 有人有任何建议/解决方案吗?
SELECT
WOPICK.DocNum,
WOPICK.ItemCode,
WOPICK.Quantity as 'Planned Qty',
BINSTOCK.WhsCode,
BINSTOCK.BinCode,
CASE WHEN (BINSTOCK.Quantity -(BINSTOCK.RunningTotalQty - WOPICK.Quantity)) <BINSTOCK.Quantity
THEN (BINSTOCK.Quantity -(BINSTOCK.RunningTotalQty - WOPICK.Quantity))
ELSE BINSTOCK.Quantity END as 'QuantityToPick'-- FinalQty
FROM (
SELECT IBQ.ItemCode, SUM(IBQ.OnHandQty)as 'Quantity',BIN.WhsCode, BIN.BinCode ,
SUM(SUM(OnHandQty)) OVER (PARTITION BY IBQ.ItemCode
ORDER BY IBQ.ItemCode,BIN.BinCode ) as 'RunningTotalQty'
FROM OIBQ IBQ INNER JOIN OBIN BIN on IBQ.BinAbs = BIN.AbsEntry
GROUP BY IBQ.ItemCode, BIN.WhsCode, BIN.BinCode
) BINSTOCK
INNER JOIN (
SELECT distinct WOR.DocNum, WOR1.LineNum, WOR1.ItemCode, WOR1.PlannedQty - WOR1.IssuedQty as 'Quantity'
FROM OWOR WOR
INNER JOIN WOR1 WOR1 on WOR.DocEntry = WOR1.DocEntry
INNER JOIN OIBQ IBQ on IBQ.ItemCode = WOR1.ItemCode
where WOR.Status = 'R'
) WOPICK on BINSTOCK.ItemCode = WOPICK.ItemCode
WHERE BINSTOCK.RunningTotalQty - BINSTOCK.Quantity < WOPICK.Quantity
order by WOPICK.LineNum;
查询子查询:
CREATE TABLE [dbo].[BINSTOCK](
ItemCode NVARCHAR(10) NOT NULL
,Quantity DECIMAL (19,6) NOT NULL
,WhsCode INT NOT NULL
,BinCode NVARCHAR (10) NOT NULL
,RunningTotalQty DECIMAL (19,6) NOT NULL
)
INSERT INTO [dbo].[BINSTOCK]
VALUES('A00001' , 7.000000, 98, '98-A001' , 7.000000),
('A00001' , 6.000000, 98, '98-A002' , 13.000000),
('A00001' , 12.000000, 98, '98-A003' , 25.000000),
('A00001' , 15.000000, 98, '98-A006' , 40.000000)
CREATE TABLE [dbo].[WOPICK](
DocNum INT NOT NULL
,LineNum INT NOT NULL
,ItemCode NVARCHAR (10) NOT NULL
,Quantity DECIMAL (19,6) NOT NULL
)
INSERT INTO [dbo].[WOPICK]
VALUES(901903,0,'A00001',12.000000),
(901904,0,'A00001',17.000000)
不带子查询的查询
-SIMPLIFIED版本(表BINSTOCK和WOPICK中的子查询结果)
SELECT
WOPICK.DocNum,
WOPICK.ItemCode,
WOPICK.Quantity as 'Planned Qty',
BINSTOCK.WhsCode,
BINSTOCK.BinCode,
CASE WHEN (BINSTOCK.Quantity -(BINSTOCK.RunningTotalQty - WOPICK.Quantity)) <BINSTOCK.Quantity
THEN (BINSTOCK.Quantity -(BINSTOCK.RunningTotalQty - WOPICK.Quantity))
ELSE BINSTOCK.Quantity END as 'QuantityToPick'-- FinalQty
FROM BINSTOCK
INNER JOIN WOPICK on BINSTOCK.ItemCode = WOPICK.ItemCode
WHERE BINSTOCK.RunningTotalQty - BINSTOCK.Quantity < WOPICK.Quantity
order by WOPICK.LineNum;
count
答案 0 :(得分:2)
这实际上比第一次听起来容易。但是,您将首先需要处理一些问题-您还需要针对所需数量进行总计:
SELECT OWOR.docNum, WOR1.itemCode, plannedQty,
SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode
ORDER BY OWOR.docEntry) - (plannedQty - issuedQty) AS prevTotalNeeded,
SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode
ORDER BY OWOR.docEntry) AS runningTotalNeeded
FROM OWOR
JOIN WOR1
ON WOR1.docEntry = OWOR.docEntry
WHERE OWOR.status = 'R'
....结合“需要运行的前一列”(并假设以前的总数量),我们现在正在查看overlapping range query。
与您的BINSTOCK
(稍作修改)结合在一起:
SELECT *
FROM (SELECT itemCode, whsCode, binCode, quantity,
SUM(quantity) OVER (PARTITION BY itemCode ORDER BY binCode) - quantity AS prevTotalQuantity,
SUM(quantity) OVER (PARTITION BY itemCode ORDER BY binCode) AS runningTotalQuantity
FROM (SELECT OIBQ.itemCode, OIBQ.whsCode, OBIN.binCode, SUM(OIBQ.onHandQty) AS quantity
FROM OIBQ
JOIN OBIN
ON OBIN.absEntry = OIBQ.binAbs
GROUP BY OIBQ.itemCode, OIBQ.whsCode, OBIN.binCode) TotalQuantity
) BINSTOCK
JOIN (SELECT OWOR.docNum, WOR1.itemCode, plannedQty,
SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode ORDER BY OWOR.docEntry) - (plannedQty - issuedQty) AS prevTotalNeeded,
SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode ORDER BY OWOR.docEntry) AS runningTotalNeeded
FROM OWOR
JOIN WOR1
ON WOR1.docEntry = OWOR.docEntry
WHERE OWOR.status = 'R') WOPICK
ON WOPICK.itemCode = BINSTOCK.itemCode
AND WOPICK.prevTotalNeeded <= BINSTOCK.runningTotalQuantity
AND WOPICK.runningTotalNeeded >= BINSTOCK.prevTotalQuantity
...将产生下表:
itemCode | whsCode | binCode | quantity | prevTotalQuantity | runningTotalQuantity | docNum | itemCode | plannedQty | prevTotalNeeded | runningTotalNeeded :------- | :------ | :------ | :-------- | :---------------- | :------------------- | -----: | :------- | :--------- | :-------------- | :----------------- A00001 | 98 | 98-A001 | 7.000000 | 0.000000 | 7.000000 | 901903 | A00001 | 12.000000 | 0.000000 | 12.000000 A00001 | 98 | 98-A002 | 6.000000 | 7.000000 | 13.000000 | 901903 | A00001 | 12.000000 | 0.000000 | 12.000000 A00001 | 98 | 98-A002 | 6.000000 | 7.000000 | 13.000000 | 901904 | A00001 | 17.000000 | 12.000000 | 29.000000 A00001 | 98 | 98-A003 | 12.000000 | 13.000000 | 25.000000 | 901904 | A00001 | 17.000000 | 12.000000 | 29.000000 A00001 | 98 | 98-A006 | 15.000000 | 25.000000 | 40.000000 | 901904 | A00001 | 17.000000 | 12.000000 | 29.000000
...。然后,通过明智的CASE
语句,我们可以将重叠的三个四个(不是三个)条件转换为最终的总计:
SELECT WOPICK.docNum, WOPICK.itemCode, WOPICK.plannedQty,
BINSTOCK.whsCode, BINSTOCK.binCode,
CASE WHEN WOPICK.prevTotalNeeded < BINSTOCK.prevTotalQuantity
AND WOPICK.runningTotalNeeded > BINSTOCK.runningTotalQuantity
THEN BINSTOCK.quantity
WHEN WOPICK.prevTotalNeeded >= BINSTOCK.prevTotalQuantity
AND WOPICK.runningTotalNeeded <= BINSTOCK.runningTotalQuantity
THEN WOPICK.neededQuantity
WHEN WOPICK.runningTotalNeeded <= BINSTOCK.runningTotalQuantity
THEN WOPICK.runningTotalNeeded - BINSTOCK.prevTotalQuantity
WHEN WOPICK.prevTotalNeeded >= BINSTOCK.prevTotalQuantity
THEN BINSTOCK.runningTotalQuantity - WOPICK.prevTotalNeeded
END AS quantityToPick
FROM (SELECT itemCode, whsCode, binCode, quantity,
SUM(quantity) OVER (PARTITION BY itemCode
ORDER BY binCode) - quantity AS prevTotalQuantity,
SUM(quantity) OVER (PARTITION BY itemCode
ORDER BY binCode) AS runningTotalQuantity
FROM (SELECT OIBQ.itemCode, OIBQ.whsCode, OBIN.binCode, SUM(OIBQ.onHandQty) AS quantity
FROM OIBQ
JOIN OBIN
ON OBIN.absEntry = OIBQ.binAbs
GROUP BY OIBQ.itemCode, OIBQ.whsCode, OBIN.binCode) TotalQuantity
) BINSTOCK
JOIN (SELECT OWOR.docNum, WOR1.itemCode, plannedQty, plannedQty - issuedQty AS neededQuantity,
SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode
ORDER BY OWOR.docEntry) - (plannedQty - issuedQty) AS prevTotalNeeded,
SUM(plannedQty - issuedQty) OVER (PARTITION BY WOR1.itemCode
ORDER BY OWOR.docEntry) AS runningTotalNeeded
FROM OWOR
JOIN WOR1
ON WOR1.docEntry = OWOR.docEntry
WHERE OWOR.status = 'R') WOPICK
ON WOPICK.itemCode = BINSTOCK.itemCode
AND WOPICK.prevTotalNeeded <= BINSTOCK.runningTotalQuantity
AND WOPICK.runningTotalNeeded >= BINSTOCK.prevTotalQuantity
Fiddle example ...产生预期的结果:
docNum | itemCode | plannedQty | whsCode | binCode | quantityToPick -----: | :------- | :--------- | :------ | :------ | :------------- 901903 | A00001 | 12.000000 | 98 | 98-A001 | 7.000000 901903 | A00001 | 12.000000 | 98 | 98-A002 | 5.000000 901904 | A00001 | 17.000000 | 98 | 98-A002 | 1.000000 901904 | A00001 | 17.000000 | 98 | 98-A003 | 12.000000 901904 | A00001 | 17.000000 | 98 | 98-A006 | 4.000000
(已省略了排序,因为原来的排序似乎不寻常。根据您的源数据,有可能在OBIN
内删除对BINSTOCK
的引用)
答案 1 :(得分:1)
这显然是存储过程的工作。甚至尝试使用查询来疯狂。 (发条回答后:编辑:Doh!)
说:
WITH Bin AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY ItemCode ORDER BY BinCode) AS BinRank
FROM BINSTOCK
), Pick AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY ItemCode ORDER BY DocNum) AS PickRank
FROM WOPICK
), BinPick AS (
SELECT
b.ItemCode,
b.Quantity AS BinQty,
b.BinCode,
b.BinRank,
p.Quantity AS PickQty,
p.DocNum,
p.PickRank,
CAST (
CASE
WHEN b.Quantity < p.Quantity
THEN b.Quantity
ELSE p.Quantity
END
AS DECIMAL) AS Picked,
CAST (
CASE
WHEN b.Quantity < p.Quantity
THEN p.Quantity - b.Quantity
ELSE 0
END
AS DECIMAL) AS Required,
CAST (
CASE
WHEN b.Quantity < p.Quantity
THEN 0
ELSE b.Quantity - p.Quantity
END
AS DECIMAL) AS Remaining,
CAST (
CASE
WHEN b.Quantity < p.Quantity
THEN null
ELSE b.BinRank
END
AS NVARCHAR) AS LastFullBinRank
FROM Bin b
JOIN Pick p ON p.ItemCode = b.ItemCode
WHERE b.BinRank = 1
AND p.PickRank = 1
UNION ALL
SELECT
ItemCode,
BinQty,
BinCode,
BinRank,
PickQty,
DocNum,
PickRank,
CAST (
CASE WHEN Remaining < Required
THEN Remaining
ELSE Required
END
AS DECIMAL) AS Picked,
CAST (
CASE WHEN Remaining < Required
THEN Required - Remaining
ELSE 0
END
AS DECIMAL) AS Required,
CAST (
CASE WHEN Remaining < Required
THEN 0
ELSE Remaining - Required
END
AS DECIMAL) AS Remaining,
CAST (
CASE WHEN Remaining < Required
THEN null
ELSE BinRank
END
AS NVARCHAR) AS LastFullBinRank
FROM (
SELECT
b.ItemCode,
b.Quantity AS BinQty,
b.BinCode,
b.BinRank,
p.Quantity AS PickQty,
p.DocNum,
p.PickRank,
bp.DocNum AS PrevDocNum,
bp.Picked,
bp.LastFullBinRank,
CASE WHEN p.DocNum = bp.DocNum
-- Same order. Continue with required from previous.
THEN bp.Required
-- New order. Required is new order quantity.
ELSE p.Quantity
END
AS Required,
CASE WHEN p.DocNum = bp.DocNum
-- Same order. Hence fresh bin. Use quanity from this bin.
THEN b.Quantity
-- New order. Hence used bin. Use remaining carried over.
ELSE bp.Remaining
END
AS Remaining
FROM BinPick bp
JOIN Pick p
ON p.ItemCode = bp.ItemCode
AND (
-- Order complete. Move to next order
(bp.Required = 0 AND p.PickRank = bp.PickRank + 1)
OR
-- Order incomlete. Continue with current Order
(bp.Required > 0 AND p.PickRank = bp.PickRank)
)
JOIN Bin b
ON b.ItemCode = bp.ItemCode
AND (
-- Order complete. Resume at last full bin.
(bp.Required = 0 AND b.BinRank = bp.LastFullBinRank)
OR
-- Order incomlete. Move to next bin.
(bp.Required > 0 AND bp.LastFullBinRank IS NULL AND b.BinRank = bp.BinRank + 1)
)
) sub1
) SELECT * FROM BinPick
注意:我几乎没有对此进行测试。我将它留给有兴趣纠正任何错误的人,但是我认为该原则是正确的。使用递归CTE来标识下一个Bin / Order,并在列中维护一堆变量以跟踪您的工作!
请参见DB Fiddle