【问题标题】:Running total in SQL with a reset condition在带有重置条件的 SQL 中运行总计
【发布时间】:2021-09-22 16:44:09
【问题描述】:

我有一个数据,它结合了不同零件的库存、销售预测和未来供应数据。我把它结合起来给我一个表格,每个月给出每个部分的净数量。见下文:

Date Part Net Quantity
30/06/2021 A 1000
31/07/2021 A -150
31/08/2021 A -200
30/09/2021 A -500
31/10/2021 A -200
30/11/2021 A -200
31/12/2021 A 50
30/06/2021 B 100
31/07/2021 B -80
31/08/2021 B 20
30/09/2021 B -30
31/10/2021 B -35
30/11/2021 B -40
31/12/2021 B -150

我需要创建一个按零件编号分区的运行总计视图,如果低于 0,则在下个月重置。如果上个月的期末库存为负,则运行总计的起点需要为 0。

我的预期结果是这样的:

Date Part Net Quantity Closing Inventory (Expected Outcome)
30/06/2021 A 1000 1000
31/07/2021 A -150 850
31/08/2021 A -200 650
30/09/2021 A -500 150
31/10/2021 A -200 -50
30/11/2021 A -200 -200
31/12/2021 A 50 50
30/06/2021 B 100 100
31/07/2021 B -80 20
31/08/2021 B 20 40
30/09/2021 B -30 10
31/10/2021 B -35 -25
30/11/2021 B -40 -40
31/12/2021 B -150 -150

我当前的代码是:

SELECT 
Date, 
Part, 
Net_Quantity, 
sum(Net_Quantity) over (partition by Part order by date) 'Closing_Inventory' 
FROM grouped

我不确定如何根据运行总计中的最后一个值创建条件,lag 函数无法查看运行总计的上一行。

【问题讨论】:

    标签: sql sql-server inventory-management


    【解决方案1】:

    这样的事情怎么办……

    [不正确的答案已删除...]

    编辑:

    --Add a column...
    ALTER TABLE PartsInventory ADD RowNumWithinPart int;
    
    --Assign row numbers partitioned by Part...
    UPDATE PartsInventory
    SET RowNumWithinPart = x.rownum
    FROM (
        SELECT ROW_NUMBER() OVER (PARTITION BY Part ORDER BY [Date]) as rownum, *
        FROM PartsInventory
    ) x
    WHERE x.Part = PartsInventory.Part AND x.Date = PartsInventory.Date
    
    --Recursive CTE solution:
    WITH InvTotalsCTE AS
    (
        SELECT [Date], RowNumWithinPart, Part, Net_Quantity, Net_Quantity as Closing_Inventory
        FROM PartsInventory
        WHERE RowNumWithinPart = 1
    
        UNION ALL
    
        SELECT Q.[Date], Q.RowNumWithinPart, Q.Part, Q.Net_Quantity, iif(P.Closing_Inventory < 0, 0, P.Closing_Inventory) + Q.Net_Quantity as Closing_Inventory
        FROM InvTotalsCTE as P
            JOIN PartsInventory Q ON (Q.RowNumWithinPart - 1) = P.RowNumWithinPart AND Q.Part = P.Part
    )
    SELECT [Date], Part, RowNumWithinPart, Net_Quantity, Closing_Inventory
    FROM InvTotalsCTE
    ORDER BY Part, RowNumWithinPart
    

    【讨论】:

    • 我已经运行了一个多小时,查询还没有加载——所以我不认为这个解决方案(即使它有效)对我来说足够有效。我只有
    • 也许你需要一个索引。 (部分,日期)是否有索引?
    • 我已经在单个部分上尝试了您的解决方案,它为每个结果返回 null
    • 我刚刚注意到我的查询是错误的。让我再试一次……
    • 这必须是视图吗?把它分成几个步骤会更简单。即使我们可以将其编写为单个查询,优化器也可能无法使其高效。
    【解决方案2】:

    如果您提供了一些示例数据会更容易,但我将如何解决这个问题:

    Declare @testData Table ([Date] date, Part char(1), NetQuantity int);
     Insert Into @testData ([Date], Part, NetQuantity)
     Values ('2021-06-30', 'A', 1000)
          , ('2021-07-31', 'A', -150)
          , ('2021-08-31', 'A', -200)
          , ('2021-09-30', 'A', -500)
          , ('2021-10-31', 'A', -200)
          , ('2021-11-30', 'A', -200)
          , ('2021-12-31', 'A',   50)
          , ('2021-06-30', 'B',  100)
          , ('2021-07-31', 'B',  -80)
          , ('2021-08-31', 'B',   20)
          , ('2021-09-30', 'B',  -30)
          , ('2021-10-31', 'B',  -35)
          , ('2021-11-30', 'B',  -40)
          , ('2021-12-31', 'B', -150);
    
       With runningTotal
         As (
     Select *
          , Inventory = sum(td.NetQuantity) over(Partition By td.Part Order By td.[Date])
       From @testData               td      
            )
     Select [Date]
          , Part
          , NetQuantity
          , ClosingInventory = iif(lag(Inventory, 1, 0) over(Partition By Part Order By [Date]) < 0, NetQuantity, Inventory)
       From runningTotal;
    

    【讨论】:

    • 这给出的结果与我的不同,但示例数据中没有显示差异。
    • 这不会返回正确的结果。如果它变为负数然后库存进入(所以再次变为正数)它将不再返回正确的结果它仍然需要净库存
    • 你有例子说明这不起作用吗?返回的结果与您的预期结果相符 - 我没有发现问题。
    猜你喜欢
    • 2018-01-25
    • 2018-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多