Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dealing with consecutive rows calculations

Assume the following situation:

  • Week 1:
    • 0 previous cases
    • 10 new cases
    • 3 resolved cases
  • Week 2:
    • 7 previous cases
    • 13 new cases
    • 15 resolved cases
  • Week 3:
    • 5 previous cases
    • 6 new cases
    • 7 resolved cases

This information is stored in a resumed table of the sort:

RESUME_TABLE:
WEEK    | TOTAL_NEW |   TOTAL_SOLVED
1       |   10      |   3
2       |   13      |   15
3       |   6       |   7

I am having a hard time build a query to obtain the following result:

REPORT_TABLE:
WEEK    |   PREV_TOTAL  |   NEW_CASES   |   SOLVED_CASES    |   NEW_TOTAL
1       |   0           |   10          |   3               |   7
2       |   7           |   13          |   15              |   5
3       |   5           |   6           |   7               |   4

The idea seems pretty trivial, NEW_TOTAL = PREV_TOTAL + NEW_CASES - SOLVED_CASES, though I have been struggling with the idea of carrying the PREV_TOTAL to the next row in order to go on.

I am trying to do it using a view over the RESUME table (Oracle 11g).

Can someone help me with some example code?

like image 739
filippo Avatar asked Apr 18 '26 10:04

filippo


2 Answers

Pretty simple and neat with analytic functions:

12:57:06 HR@vm_xe> l                                                                    
  1  select week                                                                        
  2         ,lag(total_cases_by_now - total_solved_by_now) over (order by week) prev_total
  3         ,total_new new_cases                                                        
  4         ,total_solved solved_cases                                                  
  5         ,total_cases_by_now - total_solved_by_now new_total                         
  6    from (                                                                           
  7    select week                                                                      
  8           ,total_new                                                                
  9           ,total_solved                                                             
 10           ,sum(total_new) over(order by week asc) as total_cases_by_now             
 11           ,sum(total_solved) over (order by week asc) as total_solved_by_now        
 12      from resume_table                                                              
 13* )                                                                                  
12:57:07 HR@vm_xe> /                                                                    

      WEEK   PREV_TOTAL  NEW_CASES SOLVED_CASES  NEW_TOTAL                                
---------- ------------ ---------- ------------ ----------                                
         1                      10            3          7                                
         2            7         13           15          5                                
         3            5          6            7          4                                

3 rows selected.                                                                        

Elapsed: 00:00:00.01                                                                    
like image 98
Kirill Leontev Avatar answered Apr 19 '26 23:04

Kirill Leontev


You can solve this with MODEL clause:

with resume_table as
(
    select 1 week, 10 total_new, 3 total_solved from dual union all
    select 2 week, 13 total_new, 15 total_solved from dual union all
    select 3 week, 6 total_new,  7 total_solved from dual
)
select week, prev_total, total_new, total_solved, new_total
from resume_table
model
    dimension by (week)
    measures (total_new, total_solved, 0 prev_total, 0 new_total)
    rules sequential order
    (
        new_total[any] order by week = 
            nvl(new_total[cv(week)-1], 0) + total_new[cv()] - total_solved[cv()]
        ,prev_total[any] order by week = nvl(new_total[cv(week)-1], 0)
    )
order by week;

Although this makes the assumption that WEEK is always a consecutive number. If that's not true, you will want to add a row_number(). Otherwise, the -1 may not reference the previous value.

See this SQL Fiddle.

like image 31
Jon Heller Avatar answered Apr 20 '26 00:04

Jon Heller