T-SQL逐行衰减

时间:2011-12-26 19:30:08

标签: sql-server-2008 tsql user-defined-functions

根据获得的用户积分表,我需要计算累积积分的六个月半衰期。也就是说,过去6个月赚取的所有积分均为100%,6-12个月为50%,12-18个月为25%等。

这是我使用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 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

我不完全理解这个问题,但我认为你是按用户ID来查找,所以按用户ID分组。如果您不需要按用户ID进行分组,则只需在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