问题
I have a query to get Stock-items with it's Balance and Its receiving Transactions cods with its quantity Ordered By date, And i Want to create a column which has only the proportion Balance of every RS Code according to First in First Out Principle. As An Example in the attached sample
we have StockItemId = (2222,2262,2263).
and the expected result will be AS: As in Pic the Balance of every row in RS_Portion is depending on the Quantity of the Code and the sum of RS_Portion of every item should equal the GlobalBalance of the same item.
Here's my Code:
WITH M AS (
SELECT WHS.StockItemId,SUM(WHS.OnHandBalance) AS GlobalBalance
FROM Warehouse.WarehouseStocks WHS
GROUP BY WHS.StockItemId
HAVING SUM(WHS.OnHandBalance) > 0
)
SELECT M.StockItemId,M.GlobalBalance,WHWorkOrderHeader.Code,WHWorkOrderDetails.Quantity,WHWorkOrderHeader.Date
FROM M
LEFT OUTER JOIN Warehouse.WHWorkOrderDetails
ON WHWorkOrderDetails.StockItemId = M.StockItemId
LEFT OUTER JOIN Warehouse.WHWorkOrderHeader
ON WHWorkOrderHeader.ID = WHWorkOrderDetails.WHWorkOrderHeaderId
WHERE WHWorkOrderHeader.Type = 'RS' AND M.StockItemId IN (2222,2262,2263)
ORDER BY M.StockItemId ASC, WHWorkOrderHeader.Date DESC
StockItemId,GlobalBalance,Code,Quantity,Date
2222,158.0000,RS-1-1543,1,2017-12-13 07:25:29.727
2222,158.0000,RS-1-1471,77,2017-08-22 14:53:11.880
2222,158.0000,RS-1-1470,77,2017-08-22 14:53:09.920
2222,158.0000,RS-1-1409,5,2017-02-16 13:41:00.740
2222,158.0000,RS-1-1409,5,2017-02-16 13:41:00.740
2222,158.0000,RS-1-1231,150,2015-09-29 15:41:45.000
2222,158.0000,RS-1-1226,100,2015-09-21 09:50:37.000
2262,23.0000,RS-14-371,20,2016-10-16 09:11:57.670
2262,23.0000,RS-14-334,30,2016-08-04 16:16:48.803
2262,23.0000,RS-14-303,18,2016-03-08 13:17:17.023
2262,23.0000,RS-14-301,70,2016-03-01 13:45:49.767
2262,23.0000,RS-14-298,30,2016-02-18 10:10:03.973
2262,23.0000,RS-14-286,2,2016-02-08 10:18:14.203
2262,23.0000,RS-14-285,30,2016-02-07 07:14:01.000
2262,23.0000,RS-14-280,3,2016-02-02 15:11:12.220
2262,23.0000,RS-14-276,1,2016-01-18 12:13:37.860
2262,23.0000,RS-14-274,2,2016-01-14 14:33:53.863
2262,23.0000,RS-14-273,1,2016-01-14 13:25:20.457
2262,23.0000,RS-14-271,1,2016-01-12 16:43:30.397
2262,23.0000,RS-14-270,4,2016-01-12 15:54:43.380
2262,23.0000,RS-14-268,1,2016-01-11 16:43:36.843
2262,23.0000,RS-14-267,1,2016-01-10 13:19:42.617
2262,23.0000,RS-14-266,1,2016-01-06 15:58:00.513
2262,23.0000,RS-14-261,1,2016-01-03 15:20:07.410
2262,23.0000,RS-14-259,6,2015-12-30 13:58:46.217
2262,23.0000,RS-14-258,1,2015-12-30 10:59:23.120
2262,23.0000,RS-14-250,3,2015-12-17 16:32:29.937
2262,23.0000,RS-14-245,1,2015-12-10 14:19:14.910
2262,23.0000,RS-14-240,1,2015-12-06 13:13:45.847
2262,23.0000,RS-14-236,1,2015-11-30 15:36:41.233
2262,23.0000,RS-14-233,4,2015-11-26 12:44:22.067
2262,23.0000,RS-14-228,1,2015-11-23 11:38:35.553
2262,23.0000,RS-14-226,1,2015-11-23 10:11:49.393
2262,23.0000,RS-14-223,2,2015-11-10 13:04:17.540
2263,25.0000,RS-14-301,60,2016-03-01 13:45:49.767
2263,25.0000,RS-14-298,20,2016-02-18 10:10:03.973
2263,25.0000,RS-14-295,1,2016-02-11 17:04:54.423
2263,25.0000,RS-14-294,1,2016-02-10 16:06:13.090
2263,25.0000,RS-14-293,2,2016-02-10 15:58:40.353
2263,25.0000,RS-14-276,1,2016-01-18 12:13:37.860
2263,25.0000,RS-14-274,2,2016-01-14 14:33:53.863
2263,25.0000,RS-14-271,1,2016-01-12 16:43:30.397
2263,25.0000,RS-14-268,1,2016-01-11 16:43:36.843
2263,25.0000,RS-14-267,1,2016-01-10 13:19:42.617
2263,25.0000,RS-14-266,1,2016-01-06 15:58:00.513
2263,25.0000,RS-14-259,6,2015-12-30 13:58:46.217
2263,25.0000,RS-14-258,1,2015-12-30 10:59:23.120
2263,25.0000,RS-14-250,3,2015-12-17 16:32:29.937
2263,25.0000,RS-14-240,1,2015-12-06 13:13:45.847
2263,25.0000,RS-14-236,1,2015-11-30 15:36:41.233
2263,25.0000,RS-14-223,2,2015-11-10 13:04:17.540
回答1:
This will give you the output you have provided:
WITH DataSource AS
(
SELECT *
,[GlobalBalance] - SUM([Quantity]) OVER (PARTITION BY [StockItemId], [GlobalBalance] ORDER BY [Date] DESC) AS [Dif]
,ROW_NUMBER() OVER (PARTITION BY [StockItemId], [GlobalBalance] ORDER BY [Date] DESC) [RecordID]
FROM @DataSource
), DataSourceWithPrevDiff AS
(
SELECT *
,LAG([Dif], 1, NULL) OVER (PARTITION BY [StockItemId], [GlobalBalance] ORDER BY [Date] DESC) AS [PrevDif]
FROM DataSource
)
SELECT [StockItemId]
,[GlobalBalance]
,[Date]
,[Code]
,[Quantity]
,CASE WHEN [Dif] > 0 THEN [Quantity]
WHEN [RecordID] = 1 THEN [Quantity] + [Dif]
WHEN [PrevDif] > 0 THEN [PrevDif]
END AS [RS_Portion]
FROM DataSourceWithPrevDiff
WHERE [Dif] > 0
OR [PrevDif] > 0
OR [RecordID] = 1
ORDER BY [StockItemId]
,[Date] DESC;
Of course you can split the query on parts. The idea is calculated the sum till the current row for each stoc item - balance pair. Also, we need to get the first item for each pair, too. Then in the final query we are showing the first item, the items where the sum till now is positive, or where the previous sum was positive.
Here is the full working example:
DECLARE @DataSource TABLE
(
[StockItemId] INT
,[GlobalBalance] INT
,[Code] VARCHAR(32)
,[Quantity] INT
,[Date] DATETIME2
);
INSERT INTO @DataSource ([StockItemId], [GlobalBalance], [Code], [Quantity], [Date])
VALUES ('2222', '158', 'RS-1-1543', '1', '2017-12-13 07:25:29.727')
,('2222', '158', 'RS-1-1471', '77', '2017-08-22 14:53:11.880')
,('2222', '158', 'RS-1-1470', '77', '2017-08-22 14:53:09.920')
,('2222', '158', 'RS-1-1409', '5', '2017-02-16 13:41:00.740')
,('2222', '158', 'RS-1-1409', '5', '2017-02-16 13:41:00.740')
,('2222', '158', 'RS-1-1231', '150', '2015-09-29 15:41:45.000')
,('2222', '158', 'RS-1-1226', '100', '2015-09-21 09:50:37.000')
,('2262', '23', 'RS-14-371', '20', '2016-10-16 09:11:57.670')
,('2262', '23', 'RS-14-334', '30', '2016-08-04 16:16:48.803')
,('2262', '23', 'RS-14-303', '18', '2016-03-08 13:17:17.023')
,('2262', '23', 'RS-14-301', '70', '2016-03-01 13:45:49.767')
,('2262', '23', 'RS-14-298', '30', '2016-02-18 10:10:03.973')
,('2262', '23', 'RS-14-286', '2', '2016-02-08 10:18:14.203')
,('2262', '23', 'RS-14-285', '30', '2016-02-07 07:14:01.000')
,('2262', '23', 'RS-14-280', '3', '2016-02-02 15:11:12.220')
,('2262', '23', 'RS-14-276', '1', '2016-01-18 12:13:37.860')
,('2262', '23', 'RS-14-274', '2', '2016-01-14 14:33:53.863')
,('2262', '23', 'RS-14-273', '1', '2016-01-14 13:25:20.457')
,('2262', '23', 'RS-14-271', '1', '2016-01-12 16:43:30.397')
,('2262', '23', 'RS-14-270', '4', '2016-01-12 15:54:43.380')
,('2262', '23', 'RS-14-268', '1', '2016-01-11 16:43:36.843')
,('2262', '23', 'RS-14-267', '1', '2016-01-10 13:19:42.617')
,('2262', '23', 'RS-14-266', '1', '2016-01-06 15:58:00.513')
,('2262', '23', 'RS-14-261', '1', '2016-01-03 15:20:07.410')
,('2262', '23', 'RS-14-259', '6', '2015-12-30 13:58:46.217')
,('2262', '23', 'RS-14-258', '1', '2015-12-30 10:59:23.120')
,('2262', '23', 'RS-14-250', '3', '2015-12-17 16:32:29.937')
,('2262', '23', 'RS-14-245', '1', '2015-12-10 14:19:14.910')
,('2262', '23', 'RS-14-240', '1', '2015-12-06 13:13:45.847')
,('2262', '23', 'RS-14-236', '1', '2015-11-30 15:36:41.233')
,('2262', '23', 'RS-14-233', '4', '2015-11-26 12:44:22.067')
,('2262', '23', 'RS-14-228', '1', '2015-11-23 11:38:35.553')
,('2262', '23', 'RS-14-226', '1', '2015-11-23 10:11:49.393')
,('2262', '23', 'RS-14-223', '2', '2015-11-10 13:04:17.540')
,('2263', '25', 'RS-14-301', '60', '2016-03-01 13:45:49.767')
,('2263', '25', 'RS-14-298', '20', '2016-02-18 10:10:03.973')
,('2263', '25', 'RS-14-295', '1', '2016-02-11 17:04:54.423')
,('2263', '25', 'RS-14-294', '1', '2016-02-10 16:06:13.090')
,('2263', '25', 'RS-14-293', '2', '2016-02-10 15:58:40.353')
,('2263', '25', 'RS-14-276', '1', '2016-01-18 12:13:37.860')
,('2263', '25', 'RS-14-274', '2', '2016-01-14 14:33:53.863')
,('2263', '25', 'RS-14-271', '1', '2016-01-12 16:43:30.397')
,('2263', '25', 'RS-14-268', '1', '2016-01-11 16:43:36.843')
,('2263', '25', 'RS-14-267', '1', '2016-01-10 13:19:42.617')
,('2263', '25', 'RS-14-266', '1', '2016-01-06 15:58:00.513')
,('2263', '25', 'RS-14-259', '6', '2015-12-30 13:58:46.217')
,('2263', '25', 'RS-14-258', '1', '2015-12-30 10:59:23.120')
,('2263', '25', 'RS-14-250', '3', '2015-12-17 16:32:29.937')
,('2263', '25', 'RS-14-240', '1', '2015-12-06 13:13:45.847')
,('2263', '25', 'RS-14-236', '1', '2015-11-30 15:36:41.233')
,('2263', '25', 'RS-14-223', '2', '2015-11-10 13:04:17.540');
SELECT *
,SUM([Quantity]) OVER (PARTITION BY [StockItemId], [GlobalBalance] ORDER BY [Date] DESC)
,[GlobalBalance] - SUM([Quantity]) OVER (PARTITION BY [StockItemId], [GlobalBalance] ORDER BY [Date] DESC)
FROM @DataSource
ORDER BY [StockItemId]
,[Date] DESC;
WITH DataSource AS
(
SELECT *
,[GlobalBalance] - SUM([Quantity]) OVER (PARTITION BY [StockItemId], [GlobalBalance] ORDER BY [Date] DESC) AS [Dif]
,ROW_NUMBER() OVER (PARTITION BY [StockItemId], [GlobalBalance] ORDER BY [Date] DESC) [RecordID]
FROM @DataSource
), DataSourceWithPrevDiff AS
(
SELECT *
,LAG([Dif], 1, NULL) OVER (PARTITION BY [StockItemId], [GlobalBalance] ORDER BY [Date] DESC) AS [PrevDif]
FROM DataSource
)
SELECT [StockItemId]
,[GlobalBalance]
,[Date]
,[Code]
,[Quantity]
,CASE WHEN [Dif] > 0 THEN [Quantity]
WHEN [RecordID] = 1 THEN [Quantity] + [Dif]
WHEN [PrevDif] > 0 THEN [PrevDif]
END AS [RS_Portion]
FROM DataSourceWithPrevDiff
WHERE [Dif] > 0
OR [PrevDif] > 0
OR [RecordID] = 1
ORDER BY [StockItemId]
,[Date] DESC;
回答2:
Since you didn't provide any DDL, I generated sample data, but it's clearly equivalent to yours. I hope you will be able to modify it accordingly to your needs. Try this:
declare @x table (stockItemId int, globalBalance int, quantity int, [date] date)
insert into @x values
(1,158, 1,'2018-03-31'),
(1,158, 77,'2018-03-30'),
(1,158, 77,'2018-03-29'),
(1,158, 5,'2018-03-28'),
(1,158, 5,'2018-03-27'),
(1,158, 150,'2018-03-26'),
(1,158, 100,'2018-03-25'),
(2,23, 20,'2018-03-31'),
(2,23, 77,'2018-03-30'),
(2,23, 77,'2018-03-29'),
(2,23, 5,'2018-03-28'),
(2,23, 5,'2018-03-27'),
(2,23, 150,'2018-03-26'),
(2,23, 100,'2018-03-25')
select stockItemId, globalBalance, quantity,
case when cumsum < 0 then quantity + cumSum else quantity end [RS_Portion]
from (
select stockItemId, globalBalance, quantity,
globalBalance - SUM(quantity) over (partition by stockitemid order by [date] desc rows between unbounded preceding and current row) [cumSum]
from @x
) a
--where [RS_Portion] > 0 - below is equivalent
where (case when cumsum < 0 then quantity + cumSum else quantity end) > 0
To understand this query you might need reading about window functions and cumulative sum in SQL using window functions.
回答3:
Assuming you are using SQL Server 2012 and up you can do it using FIRST_VALUE
and SUM() OVER (PARTITION BY)
I don't quite understand why you're ignoring the codes RS-1-1231
and RS-1-1226
, they were prior to the code RS-1-1409
UPDATE!!
Demo
DECLARE @Table TABLE (StockItemId int , GlobalBalance money,Code nvarchar(50), Quantity INT , [Date] DATETIME)
INSERT INTO @Table
VALUES
('2222', '158', 'RS-1-1543', '1', '2017-12-13 07:25:29.727')
,('2222', '158', 'RS-1-1471', '77', '2017-08-22 14:53:11.880')
,('2222', '158', 'RS-1-1470', '77', '2017-08-22 14:53:09.920')
,('2222', '158', 'RS-1-1409', '5', '2017-02-16 13:41:00.740')
,('2222', '158', 'RS-1-1409', '5', '2017-02-16 13:41:00.740')
,('2222', '158', 'RS-1-1231', '150', '2015-09-29 15:41:45.000')
,('2222', '158', 'RS-1-1226', '100', '2015-09-21 09:50:37.000')
,('2262', '23', 'RS-14-371', '20', '2016-10-16 09:11:57.670')
,('2262', '23', 'RS-14-334', '30', '2016-08-04 16:16:48.803')
,('2262', '23', 'RS-14-303', '18', '2016-03-08 13:17:17.023')
,('2262', '23', 'RS-14-301', '70', '2016-03-01 13:45:49.767')
,('2262', '23', 'RS-14-298', '30', '2016-02-18 10:10:03.973')
,('2262', '23', 'RS-14-286', '2', '2016-02-08 10:18:14.203')
,('2262', '23', 'RS-14-285', '30', '2016-02-07 07:14:01.000')
,('2262', '23', 'RS-14-280', '3', '2016-02-02 15:11:12.220')
,('2262', '23', 'RS-14-276', '1', '2016-01-18 12:13:37.860')
,('2262', '23', 'RS-14-274', '2', '2016-01-14 14:33:53.863')
,('2262', '23', 'RS-14-273', '1', '2016-01-14 13:25:20.457')
,('2262', '23', 'RS-14-271', '1', '2016-01-12 16:43:30.397')
,('2262', '23', 'RS-14-270', '4', '2016-01-12 15:54:43.380')
,('2262', '23', 'RS-14-268', '1', '2016-01-11 16:43:36.843')
,('2262', '23', 'RS-14-267', '1', '2016-01-10 13:19:42.617')
,('2262', '23', 'RS-14-266', '1', '2016-01-06 15:58:00.513')
,('2262', '23', 'RS-14-261', '1', '2016-01-03 15:20:07.410')
,('2262', '23', 'RS-14-259', '6', '2015-12-30 13:58:46.217')
,('2262', '23', 'RS-14-258', '1', '2015-12-30 10:59:23.120')
,('2262', '23', 'RS-14-250', '3', '2015-12-17 16:32:29.937')
,('2262', '23', 'RS-14-245', '1', '2015-12-10 14:19:14.910')
,('2262', '23', 'RS-14-240', '1', '2015-12-06 13:13:45.847')
,('2262', '23', 'RS-14-236', '1', '2015-11-30 15:36:41.233')
,('2262', '23', 'RS-14-233', '4', '2015-11-26 12:44:22.067')
,('2262', '23', 'RS-14-228', '1', '2015-11-23 11:38:35.553')
,('2262', '23', 'RS-14-226', '1', '2015-11-23 10:11:49.393')
,('2262', '23', 'RS-14-223', '2', '2015-11-10 13:04:17.540')
,('2263', '25', 'RS-14-301', '60', '2016-03-01 13:45:49.767')
,('2263', '25', 'RS-14-298', '20', '2016-02-18 10:10:03.973')
,('2263', '25', 'RS-14-295', '1', '2016-02-11 17:04:54.423')
,('2263', '25', 'RS-14-294', '1', '2016-02-10 16:06:13.090')
,('2263', '25', 'RS-14-293', '2', '2016-02-10 15:58:40.353')
,('2263', '25', 'RS-14-276', '1', '2016-01-18 12:13:37.860')
,('2263', '25', 'RS-14-274', '2', '2016-01-14 14:33:53.863')
,('2263', '25', 'RS-14-271', '1', '2016-01-12 16:43:30.397')
,('2263', '25', 'RS-14-268', '1', '2016-01-11 16:43:36.843')
,('2263', '25', 'RS-14-267', '1', '2016-01-10 13:19:42.617')
,('2263', '25', 'RS-14-266', '1', '2016-01-06 15:58:00.513')
,('2263', '25', 'RS-14-259', '6', '2015-12-30 13:58:46.217')
,('2263', '25', 'RS-14-258', '1', '2015-12-30 10:59:23.120')
,('2263', '25', 'RS-14-250', '3', '2015-12-17 16:32:29.937')
,('2263', '25', 'RS-14-240', '1', '2015-12-06 13:13:45.847')
,('2263', '25', 'RS-14-236', '1', '2015-11-30 15:36:41.233')
,('2263', '25', 'RS-14-223', '2', '2015-11-10 13:04:17.540')
;WITH Main as
(
SELECT * , FIRST_VALUE (Quantity) OVER (PARTITION BY StockItemId ORDER BY [Date]) FirstQuantity,
SUM(Quantity) OVER (PARTITION BY StockItemId) SumAllPerItem,
GlobalBalance - SUM(Quantity) OVER (PARTITION BY StockItemId ORDER BY [Date] DESC ) DiffFromMOstRecent
FROM @Table
)
,Results as
(
SELECT StockItemId , GlobalBalance , Code , Quantity , [Date], DiffFromMOstRecent ,
ISNULL(LAG(DiffFromMOstRecent) OVER (PARTITION BY StockItemId ORDER BY [Date] DESC), DiffFromMOstRecent) PrevRunningSum
,CASE WHEN Quantity = FirstQuantity THEN GlobalBalance - SumAllPerItem + Quantity ELSE Quantity END RS_Portion
FROM Main
)
,Final as
(
SELECT StockItemId , GlobalBalance , Code , Quantity , [Date]
,CASE WHEN MAX(PrevRunningSum) OVER(PARTITION BY StockItemId) < 0 then Quantity + MAX(PrevRunningSum) OVER(PARTITION BY StockItemId)
WHEN DiffFromMOstRecent < 0 THEN PrevRunningSum
ELSE RS_Portion END RS_Portion
FROM Results
)
SELECT *
FROM Final
WHERE RS_Portion >= 0
ORDER BY StockItemId , [Date] Desc
来源:https://stackoverflow.com/questions/49406634/create-a-column-to-calculate-the-portion-of-balance-for-every-shipment-according