2011-12-26 61 views
3

給定一張用戶積分表,我需要計算累計積分的六個月半衰期。也就是說,在過去的6個月內全部積分以100%的價值,50%,12-18個月25%,等等。T-SQL逐行衰減

這裏6-12個月,在使用我的最好的嘗試一個CTE:

DECLARE @t AS TABLE (
    ID int NOT NULL, 
    DT SMALLDATETIME NOT NULL, 
    POINTS int NOT NULL, 
    UserId INT NOT null, 
    POINTS_TOTAL INT NOT NULL) 
INSERT INTO @t 
VALUES (1, '1/1/2010', 20, 1, 20) 
    ,(5, '7/1/2010', 30, 1, 50) 
    ,(7, '1/1/2011', 10, 1, 60) 
    ,(8, '7/1/2011', 15, 1, 75) 
    ,(9, '12/25/2011', 15, 1, 90) 

;WITH ctePts AS 
    (SELECT t.*, POINTS AS Decay 
    FROM @t AS t 
    WHERE t.DT > DATEADD(mm, 6, GETUTCDATE()) 

    UNION ALL 

    SELECT t.ID, t.DT, t.POINTS, t.UserId, t.POINTS_TOTAL, CAST(ctePts.Decay * 0.5 + t.POINTS AS INT) AS Decay 
    FROM ctePts 
    INNER JOIN @t AS t 
     ON t.UserId = ctePts.UserId 
      AND t.DT <= ctePts.DT AND t.DT > DATEADD(mm, 6, ctePts.DT) 
) 
SELECT * 
FROM ctePts 

決賽桌將有一個HALF_LIFE列,其中包含爲該用戶贏得的所有積分的調整總和。我應該能夠運行下面的查詢來獲取用戶的當前點狀態(總累積積分些調整爲半衰期衰變)在任何給定時間點:

SELECT UserIdInt, POINTS, POINTS_HALFLIFE FROM 
    (SELECT UserIdInt, 
       ISNULL(p.POINTS_TOTAL,0) AS POINTS, ISNULL(p.POINTS_HALFLIFE,0) POINTS_HALFLIFE, 
       ROW_NUMBER() OVER (Partition BY UserIdInt ORDER BY p.ID DESC) AS rownum 

    FROM dbo.USER_POINTS p) a 
WHERE rownum = 1 

回答

2

這是你需要什麼?

SELECT *, 
     POINTS/POWER(2E0, ((DATEDIFF(MONTH, DT, GETUTCDATE()) - 1 + 
          CASE 
          WHEN DAY(DT) <= DAY(GETUTCDATE()) THEN 1 
          ELSE 0 
          END)/6)) 
      AS POINTS_HALFLIFE 
FROM @t 

返回

ID   DT      POINTS  UserId  POINTS_TOTAL POINTS_HALFLIFE 
----------- ----------------------- ----------- ----------- ------------ ---------------------- 
1   2010-01-01 00:00:00  20   1   20   2.5 
5   2010-07-01 00:00:00  30   1   50   7.5 
7   2011-01-01 00:00:00  10   1   60   5 
8   2011-07-01 00:00:00  15   1   75   15 
9   2011-12-25 00:00:00  15   1   90   15 
+0

如果這就是他所尋找的那是光滑的。 +1使用POWER。 – Paparazzi 2011-12-26 21:53:23

+0

同意。我的問題可能更清楚。將爲後人編輯。雖然不是我的意圖,但這個答案會讓我在那裏。我第二個BalamBalam。非常光滑的優化方法。 +1。 – Laramie 2011-12-26 22:14:03

0

我不完全理解這個問題,但我認爲你正在尋找通過用戶ID,以便按用戶ID。如果你不需要通過userID進行分組,那麼只需在select和group by中刪除它。

select base.UserId, SUM([full].[POINTS]) as [fullPoints], SUM([half].[POINTS])/2 as [halfPoints] 
    , SUM([quarter].[POINTS])/4 as [quarterPoints] 
    , (SUM([full].[POINTS]) + SUM([half].[POINTS])/2 + SUM([quarter].[POINTS])/4) as [totalPoints] 
    from @t as [base] 
    left outer join @t as [full] 
     on base.ID = [full].ID 
     and DATEDIFF(MM, [full].DT, GETDATE()) <= 6 
    left outer join @t as [half] 
     on base.ID = [half].ID 
     and DATEDIFF(MM, [half].DT, GETDATE()) > 6 
     and DATEDIFF(MM, [half].DT, GETDATE()) <= 12 
    left outer join @t as [quarter] 
     on base.ID = [quarter].ID 
     and DATEDIFF(MM, [quarter].DT, GETDATE()) > 12 
    group by base.UserId