T-SQL Row by Row Decay - PullRequest
       23

T-SQL Row by Row Decay

3 голосов
/ 26 декабря 2011

Учитывая таблицу заработанных очков, мне нужно рассчитать шестимесячный период полураспада накопленных очков.То есть все очки, заработанные за последние 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 ]

2 голосов
/ 27 декабря 2011

Это то, что вам нужно?

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 голосов
/ 27 декабря 2011

Я не до конца понимаю вопрос, но думаю, что вы ищете по ИД пользователя, поэтому сгруппируйте по ИД пользователя.Если вам не нужно группировать по ИД пользователя, просто удалите его в списке выбора и сгруппируйте по.

    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
...