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

时间:2018-12-19 18:50:50

标签: sql sql-server tsql recursive-query

我有一个表dbo.TrueMarginCalc,我需要执行该表以根据日期计算加权成本。我也有此电子表格,它说明了我需要做的事情。数据库中的表就是这样。

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

enter image description here

然后我需要使用前一天的“加权真实费用”再次递归计算,依此类推:

enter image description here enter image description here

我的代码是这样的:

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锚点完全相同的计算。

2 个答案:

答案 0 :(得分:1)

您可以为此使用递归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

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

答案 1 :(得分:0)

我对公式不是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