Текущая сумма с максимальным и минимальным ограничением в SQL Server - PullRequest
4 голосов
/ 08 ноября 2019

У меня есть таблица, которая выглядит следующим образом

|ID1| ID2| Date       |count |
+---+----+------------+------+
|1  | 1  | 2019-07-24 | 3    | 
|1  | 1  | 2019-07-25 | 3    |
|1  | 1  | 2019-07-26 | 3    |
|1  | 1  | 2019-07-27 | 1    |
|1  | 1  | 2019-07-28 | -3   |
|1  | 2  | 2019-07-24 | 1    |
|1  | 2  | 2019-07-25 | -3   |
|1  | 2  | 2019-07-26 | 3    |
|1  | 2  | 2019-07-27 | 3    |
|1  | 2  | 2019-07-28 | 3    |

Я заинтересован в расчете промежуточной суммы с минимальным ограничением 0 и максимальным ограничением 8. Результирующая таблица будет выглядеть следующим образом.

|ID1| ID2| Date       |count |runningSum|
+---+----+------------+------+----------+
|1  | 1  | 2019-07-24 | 3    | 3        |
|1  | 1  | 2019-07-25 | 3    | 6        |
|1  | 1  | 2019-07-26 | 3    | 8        |
|1  | 1  | 2019-07-27 | 1    | 8        |
|1  | 1  | 2019-07-28 | -3   | 5        |
|1  | 2  | 2019-07-24 | 1    | 1        |
|1  | 2  | 2019-07-25 | -3   | 0        |
|1  | 2  | 2019-07-26 | 3    | 3        |
|1  | 2  | 2019-07-27 | 3    | 6        |
|1  | 2  | 2019-07-28 | 3    | 8        |

Я знаю, что у Oracle есть много разных решений для решения этой проблемы, как описано здесь в номере 7 https://blog.jooq.org/2016/04/25/10-sql-tricks-that-you-didnt-think-were-possible/. Делает что-нибудь столь же простое, как это существует для Microsoft SQL Server.

Обратите внимание, что я не могу создавать таблицы, временные таблицы или переменные таблиц.

EDIT Я использую Azure Datawarehouse, где рекурсивные операторы CTE и курсор недоступны. Неужели нет других способов решить эту проблему в SQL Server?

1 Ответ

2 голосов
/ 08 ноября 2019

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

Рекурсивный CTE выполняет итерацию, поэтому он может делать то, что вы хотите:

with t as (
      select t.*,
             row_number() over (partition by id1, id2 order by date) as seqnum
      from <yourtable> t
     ),
     cte as (
      select id1, id2, date, count,
             (case when count < 0 then 0
                   when count > 8 then 8
                   else count
              end) as runningsum,
             seqnum
      from t
      where seqnum = 1
      union all
      select cte.id1, cte.id2, t.date, t.count,
             (case when t.count + cte.runningsum < 0 then 0
                   when t.count + cte.runningsum > 8 then 8
                   else t.count + cte.runningsum
              end) as runningsum, t.seqnum
      from cte join
           t
           on t.seqnum = cte.seqnum + 1 and
              t.id1 = cte.id1 and t.id2 = cte.id2
     )
select *
from cte
order by id1, id2, date;

Здесь - это db <> fiddle.

Обратите внимание, что очень похожий код будет работать в Oracle 12C, который поддерживает рекурсивные CTE. В более ранних версиях Oracle вы можете использовать connect by.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...