Oracle PL / SQL SUM OVER( ) , начиная с определенной строки

#sql #oracle #for-loop #plsql

#sql #Oracle #for-цикл #plsql

Вопрос:

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

 Pam_A   Week   Value_1  
A       1        10
A       2        13
B       3        15
B       4        10
B       5        11 
B       6        10
  

Я хочу добиться следующего:

 Pam_A   Week   Value_1  Value_2
A       1        10
A       2        13
B       3        15      28  
B       4        10      38
B       5        11      49
B       6        10      59
  

Когда Pam_A=B, суммируйте текущее Значение_1 и его предыдущее значение в строке и продолжайте увеличивать это значение в соответствии со следующим значением в Значении_1

Есть идеи для достижения этой совокупной суммы?

Ответ №1:

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

 with t(Pam_A, Week, Value_1) as (
   select 'A',       1,        10 from dual union all
   select 'A',       2,        13 from dual union all
   select 'B',       3,        15 from dual union all
   select 'B',       4,        10 from dual union all
   select 'B',       5,        11 from dual union all 
   select 'B',       6,        10 from dual
)
   select
      Pam_A, Week, Value_1
     ,case 
         when Pam_A='B' or lead(Pam_A)over(order by week) = 'B' 
          then 'Y' 
          else 'N' 
      end as flag
   from t;
  

Результаты:

 PAM_A       WEEK    VALUE_1 FLAG
----- ---------- ---------- ----
A              1         10 N
A              2         13 Y
B              3         15 Y
B              4         10 Y
B              5         11 Y
B              6         10 Y

6 rows selected.
  

Затем вы можете агрегировать только те строки, которые имеют flag =’Y’:

 with t(Pam_A, Week, Value_1) as (
   select 'A',       1,        10 from dual union all
   select 'A',       2,        13 from dual union all
   select 'B',       3,        15 from dual union all
   select 'B',       4,        10 from dual union all
   select 'B',       5,        11 from dual union all 
   select 'B',       6,        10 from dual
)
select
   v.*
  ,case 
      when flag='Y' and Pam_a='B'
         then sum(Value_1)over(partition by flag order by Week) 
   end as sums
from (
   select
      Pam_A, Week, Value_1
     ,case 
         when Pam_A='B' or lead(Pam_A)over(order by week) = 'B' 
          then 'Y' 
          else 'N' 
      end as flag
   from t
) v;
  

Результаты:

 PAM_A       WEEK    VALUE_1 FLAG       SUMS
----- ---------- ---------- ---- ----------
A              1         10 N
A              2         13 Y
B              3         15 Y            28
B              4         10 Y            38
B              5         11 Y            49
B              6         10 Y            59

6 rows selected.
  

Ответ №2:

Используя комбинацию LEAD SUM аналитических функций и, вы можете определить, в каких строках следующий PAM_A имеет значение B, только SUM если следующая строка — B или текущая строка — B.

Запрос

 WITH
    d (pam_a, week, value_1)
    AS
        (SELECT 'A', 1, 10 FROM DUAL
         UNION ALL
         SELECT 'A', 2, 13 FROM DUAL
         UNION ALL
         SELECT 'B', 3, 15 FROM DUAL
         UNION ALL
         SELECT 'B', 4, 10 FROM DUAL
         UNION ALL
         SELECT 'B', 5, 11 FROM DUAL
         UNION ALL
         SELECT 'B', 6, 10 FROM DUAL)
SELECT pam_a,
       week,
       value_1,
       CASE
           WHEN pam_a = 'B'
           THEN
               SUM (CASE WHEN next_pam_a = 'B' OR pam_a = 'B' THEN value_1 ELSE 0 END)
                   OVER (ORDER BY week)
           ELSE
               NULL
       END    value_2
  FROM (SELECT pam_a, week, value_1, LEAD (pam_a) OVER (ORDER BY week) AS next_pam_a FROM d);
  

Результат

    PAM_A    WEEK    VALUE_1    VALUE_2
________ _______ __________ __________
A              1         10
A              2         13
B              3         15         28
B              4         10         38
B              5         11         49
B              6         10         59
  

Ответ №3:

Если я понимаю, вам нужна совокупная сумма, но с условностью:

 select t.*,
       (case when pam_A = 'B' then sum(value_1) over (order by week) end) as value_2
from t;