Create a column to calculate the portion of balance for every shipment according to FIFO

此生再无相见时 提交于 2021-01-05 12:36:14

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!