Как рассчитать промежуточную сумму значения, которое зависит от самой промежуточной суммы в Oracle SQL - PullRequest
1 голос
/ 07 февраля 2020

Я пытаюсь вычислить значение и промежуточную сумму значения, которые зависят от самой промежуточной суммы. Промежуточный итог должен суммировать последние четыре значения, если промежуточный итог меньше или равен 3. Если промежуточный итог больше 3, то четвертое добавляемое значение должно быть уменьшено на [running_total - 3]. Если значение должно было быть уменьшено, то последующие промежуточные итоги должны учитывать уменьшенное значение вместо исходного значения.

Любые идеи о том, как решить эту проблему в Oracle SQL?

Пример

С учетом следующих данных:

create table val_table (id number, val number);

insert into val_table values (1, 0); 
insert into val_table values (2, 2); 
insert into val_table values (3, 0); 
insert into val_table values (4, 0); 
insert into val_table values (5, 2); 
insert into val_table values (6, 0); 
insert into val_table values (7, 3); 
insert into val_table values (8, 0); 
insert into val_table values (9, 3); 
insert into val_table values (10,0); 
commit;

Обычная общая сумма

select id
      ,val
      ,sum(val) over (order by id rows between 3 preceding and current row) as running_total
from val_table
);

выходы

============================
| ID | VAL | RUNNING_TOTAL |
|--------------------------|
| 1  |  0  |    0          |
| 2  |  2  |    2          |
| 3  |  0  |    2          |
| 4  |  0  |    2          |
| 5  |  2  |    4          |
| 6  |  0  |    2          |
| 7  |  3  |    5          |
| 8  |  0  |    5          |
| 9  |  3  |    6          |
| 10 |  0  |    6          |
============================

Требуемые откорректированные значения и откорректированные итоги работы:

====================================================
| ID | VAL | VAL_ADJUSTED | RUNNING_TOTAL_ADJUSTED |
|--------------------------------------------------|
| 1  |  0  |      0       |            0           |
| 2  |  2  |      2       |            2           |
| 3  |  0  |      0       |            2           |
| 4  |  0  |      0       |            2           |
| 5  |  2  |      1       |            3           |
| 6  |  0  |      0       |            1           | 
| 7  |  3  |      2       |            3           |
| 8  |  0  |      0       |            3           |
| 9  |  3  |      1       |            3           | 
| 10 |  0  |      0       |            3           | 
====================================================

Обратите внимание, что откорректированное значение ID = 7 приводит к 2. Откорректированное итоговое значение при ID = 7 будет 0 + 1 + 0 + 3 = 4, что больше 3. Следовательно, значение ID = 7 должно быть уменьшено на 1, в результате чего скорректированное значение равно 2.

Пример 2

С учетом следующих данных:

create table val_table2 (id number, val number);

insert into val_table2 values (1, 2); 
insert into val_table2 values (2, 2); 
insert into val_table2 values (3, 2); 
insert into val_table2 values (4, 2); 
insert into val_table2 values (5, 2); 
commit;

Требуемые откорректированные значения и откорректированные итоги работы являются

====================================================
| ID | VAL | VAL_ADJUSTED | RUNNING_TOTAL_ADJUSTED |
|--------------------------------------------------|
| 1  |  2  |      2       |            2           |
| 2  |  2  |      1       |            3           |
| 3  |  2  |      0       |            3           |
| 4  |  2  |      0       |            3           |
| 5  |  2  |      2       |            3           |
====================================================

Ответы [ 2 ]

1 голос
/ 07 февраля 2020

Вы хотите что-то подобное (но я не могу понять, как вы получили ваши скорректированные значения):

SELECT id,
       val,
       val_adjusted,
              SUM( val_adjusted ) OVER (
         ORDER BY id
         ROWS BETWEEN 3 PRECEDING AND CURRENT ROW
       ) AS running_total_adjusted
FROM   (
  SELECT id,
         val,
         GREATEST(
           CASE
           WHEN running_total > 3
           THEN val - (running_total - 3)
           ELSE val
           END,
           0
         ) AS val_adjusted
  FROM   (
    SELECT id,
           val,
           SUM(val) OVER (
             ORDER BY id
             ROWS BETWEEN 3 PRECEDING AND CURRENT ROW
           ) AS running_total
    FROM   val_table
  )
);

, который выводит:

ID | VAL | VAL_ADJUSTED | RUNNING_TOTAL_ADJUSTED
-: | --: | -----------: | ---------------------:
 1 |   0 |            0 |                      0
 2 |   2 |            2 |                      2
 3 |   0 |            0 |                      2
 4 |   0 |            0 |                      2
 5 |   2 |            1 |                      3
 6 |   0 |            0 |                      1
 7 |   3 |            1 |                      2
 8 |   0 |            0 |                      2
 9 |   3 |            0 |                      1
10 |   0 |            0 |                      1

дБ <> скрипка здесь

0 голосов
/ 07 февраля 2020

Привет, насколько я понимаю:

При выполнении свертывания 4 процедур мы берем скорректированные значения, что означает, что для получения скорректированного значения в строке x необходимо знать скорректированное значение его 3 предшествующее. Вот код, который я написал для этого:

cte1 получает корректирующее значение, говорящее нам о том, на сколько равна строка x из 3, если мы добавим 3, предшествующие ее значению

cte2 просто принудительно устанавливает значение корректировки на 0 для строки со значением 0

ct3 использует коэффициент регулировки с val и значениями 3, предшествующими для вычисления val_adjusted Окончательный запрос создает окончательную функцию windows на основе VAL_ADJUSTED

; with cte as
(
select id
      ,val
      ,case when sum(val) over (order by id rows between 3 preceding and current row) > 3 then 3 else sum(val) over (order by id rows between 3 preceding and current row) end as running_total
      ,case when 3 - sum(val) over (order by id rows between 3 preceding and current row) >= 0 then val else 3 - sum(val) over (order by id rows between 3 preceding and current row) end as adjustmentfactor
from val_table
),
cte2 as
(
select 
 id, val,
 case when val = 0 then 0 else abs(adjustmentfactor) end as adjustmentfactor
from cte
),
cte3 as
(
select 
 id, val, abs(adjustmentfactor) as adjustmentfactor ,
  case when val = 0 then 0 else
       case when 3 - sum(adjustmentfactor) over (order by id rows between 3 preceding and current row) < 0 then 
            val - (sum(adjustmentfactor) over (order by id rows between 3 preceding and current row) - 3)
       else
            adjustmentfactor
       end 
 end as VAL_ADJUSTED 
from cte2
)
select id, val, VAL_ADJUSTED,
sum(VAL_ADJUSTED) over (order by id rows between 3 preceding and current row) as RUNNING_TOTAL_ADJUSTED 
from cte3
;

Выходные данные:

id  val    VAL_ADJUSTED RUNNING_TOTAL_ADJUSTED
1   0              0        0
2   2              2        2
3   0              0        2
4   0              0        2
5   2              1        3
6   0              0        1
7   3              2        3
8   0              0        3
9   3              1        3
10  0              0        3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...