根据前几天的计算进行递归计算

Perform recursive calculation based on previous days calculation

我有一个 table dbo.TrueMarginCalc,我需要根据日期计算加权成本。我还有这个电子表格,它说明了我需要做什么。数据库中的table就是这样的

在下图中,这个 table 按 [日期] ASC 排序,我这样计算第一个实例:

然后我需要使用前一天的 "Weighted True Cost" 再次递归计算,依此类推:

我的代码是这样的:

CREATE TABLE dbo.TrueMarginCalc 
(
    [WHS] varchar(3),
    [PRODUCT] varchar(5),
    [TRANS DATE] DATE,
    [RECEIPTS] INT,
    [TRUE COST] NUMERIC(18,8),
    [RUNNING_SALES] INT,
)

INSERT INTO dbo.TrueMarginCalc 
SELECT 
'350','54710','2018-09-06',42,0.7128,52   UNION ALL SELECT
'350','54710','2018-09-07',42,0.7154,61   UNION ALL SELECT
'350','54710','2018-09-08',42,0.715 ,42   UNION ALL SELECT
'350','54710','2018-09-10',0    ,0  ,37   UNION ALL SELECT
'350','54710','2018-09-11',42,0.7124,44   UNION ALL SELECT
'350','54710','2018-09-12',42,0.7125,42   UNION ALL SELECT
'350','54710','2018-09-13',42,0.7147,77   UNION ALL SELECT
'350','54710','2018-09-14',0    ,0  ,35   UNION ALL SELECT
'350','54710','2018-09-15',42,0.7123,47   UNION ALL SELECT
'350','54710','2018-09-17',0    ,0  ,22   UNION ALL SELECT
'350','54710','2018-09-18',42,0.7183,45   UNION ALL SELECT
'350','54710','2018-09-19',42,0.71  ,42   UNION ALL SELECT
'350','54710','2018-09-20',42,0.7124,56   UNION ALL SELECT
'350','54710','2018-09-21',0    ,0  ,10   UNION ALL SELECT
'350','54710','2018-09-22',42,0.7124,43   UNION ALL SELECT
'350','54710','2018-09-24',0    ,0  ,0    UNION ALL SELECT
'350','54710','2018-09-25',42,0.71  ,41   UNION ALL SELECT
'350','54710','2018-09-26',42,0.71  ,54    

select *, (Running_Sales*[TRUE COST])/NULLIF(Running_Sales,0) As [Weighted True Cost] 
FROM dbo.TrueMarginCalc order by [TRANS DATE]

这只是计算第一天的加权真实成本。这是否需要某种游标或递归才能在 T-SQL?

中执行此操作
;
WITH CTE AS (

select ROW_NUMBER() OVER (PARTITION BY WHS, PRODUCT ORDER BY [TRANS DATE]) AS RNK, WHS,PRODUCT,[TRANS DATE], [RECEIPTS], [TRUE COST], RUNNING_SALES
, CAST((Running_Sales*[TRUE COST])/NULLIF(Running_Sales,0) AS MONEY) As [Weighted True Cost] FROM dbo.TrueMarginCalc 

UNION ALL

select ROW_NUMBER() OVER (PARTITION BY WHS, PRODUCT ORDER BY [TRANS DATE]) AS RNK, WHS,PRODUCT,[TRANS DATE], [RECEIPTS], [TRUE COST], RUNNING_SALES
, CAST((Receipts*[TRUE COST])+([Weighted True Cost] * Running_Sales)/(Receipts+Running_Sales) AS MONEY) AS [Weighted True Cost] FROM CTE 
WHERE RNK = RNK - 1 
)
SELECT * FROM CTE
ORDER BY [TRANS DATE] asc

上面的代码在理论上是我需要的,但我肯定是错误地使用了终结符,因为它吐出与递归 CTE 的锚点完全相同的计算。

我不是 100% 了解这个公式,但你可以试试这个。

SELECT WHS, PRODUCT, [TRANS DATE], RECEIPTS, [TRUE COST], [RUNNING_SALES]
    , (
        CASE [TRUE COST]
            WHEN 0.0 THEN LAG([True Cost]) OVER(PARTITION BY WHS, PRODUCT ORDER BY [TRANS DATE])
            ELSE (COALESCE( LAG([True Cost]) OVER(PARTITION BY WHS, PRODUCT ORDER BY [TRANS DATE]), [TRUE COST] ) + [True Cost]) / 2
        END
    ) AS [WeightedTrueCost]
FROM dbo.TrueMarginCalc

您可以为此使用递归 cte,例如:

WITH cte AS (
    -- numbering is required for rcte
    SELECT *, ROW_NUMBER() OVER (PARTITION BY WHS, PRODUCT ORDER BY TRANS_DATE) AS rn
    FROM TrueMarginCalc
), rcte AS (
    -- base row for each partition
    SELECT *, CAST(TRUE_COST * RUNNING_SALES / TRUE_COST AS DECIMAL(18, 8)) AS WTC
    FROM cte AS base
    WHERE rn = 1
    UNION ALL
    -- next row for each partition
    SELECT curr.*, CAST(prev.WTC * curr.RUNNING_SALES / curr.TRUE_COST AS DECIMAL(18, 8))
    FROM cte AS curr
    INNER JOIN rcte AS prev ON curr.WHS = prev.WHS AND curr.rn = prev.rn + 1
)
SELECT *
FROM rcte

不幸的是,公式不完整,但上面的查询向您展示了如何访问当前行和上一次迭代中的列。