Скользящая сумма в SQL, которая сбрасывается в 0, если значение превышает 90 - PullRequest
1 голос
/ 03 апреля 2020

Первый пост. Обучение SQL за последние 6 месяцев, поэтому помощь приветствуется. У меня есть данные, структурированные как показано ниже:

DECLARE @tmp4 as TABLE (
    AccountNumber int,
    Date            date,
    DateRank        int
)

INSERT INTO @tmp4
VALUES (001, '11/13/2018' , 1)
, (002, '12/19/2018', 2)
, (003, '1/23/2019' , 3)
, (004, '2/5/2019' , 4)
, (005, '3/10/2019' , 5)
, (006, '3/20/2019' , 6)
, (007, '4/8/2019' , 7)
, (008, '5/20/2019' , 8)

Что мне нужно сделать с этими данными, это вычислить скользящий итог, который сбрасывается в 0 после достижения порога в 90 дней. Я использовал функцию DateDiff для вычисления DateDiff между последовательными датами и пробовал несколько вещей, используя LAG и другие оконные функции, но не могу сбросить их. Цель состоит в том, чтобы найти «посещение индекса», которое может происходить только один раз каждые 90 дней. Таким образом, мой план состоит в том, чтобы при первом посещении поле показывало 0 и сбрасывалось на 0 для следующего пребывания после истечения 90 дней с момента первого посещения, а затем выполнялось только посещение со значением 0.

Одно решение Я пытался быть правильным для большинства наборов, но не возвращал правильные значения для вышеуказанного набора (строки 4 и 8 должны начинаться заново как "посещения индекса"). Результаты, которые я ожидаю получить по этому запросу:

Account   Date         DateRank   RollingTotal

001     |'11/13/2018' | 1        | 0
002     |'12/19/2018' | 2        | 35
003     |'1/23/2019'  | 3        | 71
004     |'2/5/2019'   | 4        | 84
005     |'3/10/2019'  | 5        | 0  (not 117)
006     |'3/20/2019'  | 6        | 10 
007     |'4/8/2019'   | 7        | 29
008     |'5/20/2019'  | 8        | 71

Спасибо за любую помощь.

Вот код, который я пробовал:

DECLARE @tmp2 as TABLE
(EmrNumber      varchar(255)
, AdmitDateTime datetime
, DateRank      int
, LagDateDiff   int
, RunningTotal  int
)

INSERT INTO @tmp2

SELECT tmp1.EmrNumber
        , tmp1.AdmitDateTime
        , tmp1.DateRank
--, LAG(tmp1.AdmitDateTime) OVER(PARTITION BY tmp1.EmrNumber ORDER BY tmp1.DateRank) as NextAdmitDate
, -DATEDIFF(DAY, tmp1.AdmitDateTime, LAG(tmp1.AdmitDateTime) OVER(PARTITION BY tmp1.EmrNumber ORDER BY tmp1.DateRank)) LagDateDiff
, IIF((SELECT SUM(sumt.total)
        FROM (
                SELECT -DATEDIFF(DAY, tmpsum.AdmitDateTime, LAG(tmpsum.AdmitDateTime) OVER(PARTITION BY tmpsum.EmrNumber ORDER BY tmpsum.DateRank)) total
                FROM @tmp tmpsum
                WHERE tmp1.EmrNumber = tmpsum.EmrNumber 
                AND tmpsum.AdmitDateTime <= tmp1.AdmitDateTime
        ) sumt) IS NULL, 0, (SELECT SUM(sumt.total)
        FROM (
                SELECT -DATEDIFF(DAY, tmpsum.AdmitDateTime, LAG(tmpsum.AdmitDateTime) OVER(PARTITION BY tmpsum.EmrNumber ORDER BY tmpsum.DateRank)) total
                FROM @tmp tmpsum
                WHERE tmp1.EmrNumber = tmpsum.EmrNumber 
                AND tmpsum.AdmitDateTime <= tmp1.AdmitDateTime
        ) sumt) ) as RunningTotal 

FROM @tmp tmp1 

SELECT *
, CASE WHEN LagDateDiff >90 THEN 0
    WHEN RunningTotal = 0 THEN 0
    ELSE LAG(LagDateDiff) OVER(PARTITION BY EmrNumber ORDER BY DateRank) + RunningTotal END AS RollingTotal
FROM @tmp2

1 Ответ

0 голосов
/ 03 апреля 2020

Для этого нужен рекурсивный запрос, потому что итоговая сумма должна проверяться итеративно, строка за строкой:

with cte as (
    select 
        Account, 
        Date, 
        DateRank, 
        0 RollingTotal
    from @tmp4
    where DateRank = 1
    union all
    select 
        t.Account, 
        t.Date,
        t.DateRank,
        case when RollingTotal + datediff(day, c.Date, t.Date) > 90
            then 0
            else RollingTotal  + datediff(day, c.Date, t.Date)
        end
    from cte c
    inner join @tmp4 t on t.DateRank = c.DateRank + 1
)
select * from cte

Якорь cte выбирает первую запись (как указано DateRank Затем рекурсивная часть обрабатывает строки одну за другой и сбрасывает счетчик операций, когда она пересекает 90.

...