oracle sql running total range

#sql #oracle #oracle11g

#sql #Oracle #oracle11g

Вопрос:

У меня есть две таблицы tab_a как

    SUB_ID AMOUNT
    1     10
    2     5
    3     7
    4     15
    5     4
  

2 таблица tab_b как

     slab_number slab_start slab_end 
    1             12          20
    2             21          25
    3             26          35
  

значение slab_start всегда будет на 1 больше, чем значение slab_end предыдущего номера сляба

Если я выполню текущий итог для tab_a, мой результат будет

  select sub_id , sum(amount)  OVER(ORDER BY sub_id) run_sum
from tab_a

sub_id run_sum
  1     10
  2     15
  3     22
  4     37
  5     41
  

Мне нужно выполнить SQL-запрос, чтобы проверить, какой slab_NUMBER, если run_sum меньше первого slab_number, тогда он должен быть равен нулю, если run_sum больше последнего номера slab, тогда пустым, кроме строки, которая пересекает предел.
Ожидаемый результат

   sub_id run_sum slab_number
      1     10    0
      2     15    1
      3     22    2
      4     37    3
      5     41    NULL
  

Я пробовал это .

Сначала найдите текущую сумму, которая пересекает предел, т.е. последний slab_end

         select min(  run_sum ) 
              from  (select sub_id , sum(amount)  OVER(ORDER BY sub_id) run_sum
from tab_a ) where run_sum>=35
  

затем используйте следующий запрос

 select sub_id,
       run_sum,
       case
         when run_sum <
              (select SLAB_START from tab_b where slab_number = '1') then
          0
         when run_sum = 37 then
          (select max(slab_number) from tab_b)
         when run_sum > 37 then
          NULL
         else
          (select slab_number
             from tab_b
            where run_sum between SLAB_START and slab_end)
       end slab_number
  from (select sub_id, sum(amount) OVER(ORDER BY sub_id) run_sum from tab_a)
  

есть ли какой-либо другой способ улучшить.

Комментарии:

1. Создайте сохраненную функцию для извлечения slab_number и используйте ее в запросе…

Ответ №1:

Несколько странное требование 🙂 Используйте некоторые аналитические функции и case when ‘ы. Row_number когда вам нужно сначала что-то найти max() over() и sum() over() когда вам нужна информация из более чем строк:

 with  
  a as (
    select sub_id, row_number() over (order by sub_id) rn, 
           sum(amount) over (order by sub_id) rs 
      from tab_a),
  b as (select tab_b.*, max(slab_number) over () msn from tab_b )
select sub_id, rs, 
       case when sn is null and row_number() over (partition by sn order by sub_id) = 1 
            then msn else sn 
       end sn
  from (
    select sub_id, rs, max(msn) over () msn,
           case when slab_number is null and rn = 1 then 0 else slab_number end sn
      from a left join b on rs between slab_start and slab_end)
  

демонстрация dbfiddle

Ответ №2:

вы могли бы попробовать это:

 select a.sub_id , sum(a.amount)  OVER(ORDER BY a.sub_id) run_sum
 ,case when b.slab_number=1 then 0 else  lag(b.slab_number,1) over (order by a.sub_id)end slab_number
from tab_a a
left join tab_b b on a.SUB_ID = b.slab_number
  

Ответ №3:

Я думаю, что это в основном a left join со значением по умолчанию:

 select a.*,
       (case when a.run_sum < bb.min_slab_num then 0
             else b.slab_num
        end) as slab_num
from (select sub_id,
             sum(amount) over (order by sub_id) as run_sum
      from tab_a
     ) a left join
     tab_b b
     on a.run_sum between slab_start and slab_end cross join
     (select min(slab_start) as min_slab_start
      from tab_b
     ) bb;