Pergunta

I need to create table with cumulative sum that for: - sum of value and null gives null if there isn't further in row any value

My initial table, from which I want to create that cumulative sum looks like:

+--------------------+---------------+------+-----+---------+-------+
| First_mob          | r2009         | r2010|r2011| r2012   | r2013 |
+--------------------+---------------+------+-----+---------+-------+
| 0                  | 1             | NULL |NULL | NULL    |NULL   |
| 1                  | 3             | 1    | 2   | 3       |3      |
| 2                  | 6             | 6    | 3   | NULL    |NULL   |
| 3                  | 10            | 17   | NULL| NULL    |5      |
| 4                  | 61            | 23   | NULL| 4       |NULL   | 
+--------------------+---------------+------+-----+---------+-------+

Table which I want obtain looks like

+--------------------+---------------+------+-----+---------+-------+
| First_mob          | r2009         | r2010|r2011| r2012   | r2013 |
+--------------------+---------------+------+-----+---------+-------+
| 0                  | 1             | NULL |NULL | NULL    |NULL   |
| 1                  | 4             | 1    | 2   | 3       |3      |
| 2                  | 10            | 7    | 5   | 3       |3      |
| 3                  | 20            | 24   | NULL| 3       |8      |
| 4                  | 81            | 47   | NULL| 7       |NULL   | 
+--------------------+---------------+------+-----+---------+-------+

My sql code for cumulative sum looks like:

if OBJECT_ID('tempdb..#suma_risk_prestige_nbr') IS NOT NULL  drop table             #suma_risk_prestige_nbr
select tp1.first_mob_InDef,
       SUM(tp2.r2007) as r2007,
   SUM(tp2.r2008) as r2008,
   SUM(tp2.r2009) as r2009,
   SUM(tp2.r2010) as r2010,
   SUM(tp2.r2011) as r2011,
   SUM(tp2.r2012) as r2012,
   SUM(tp2.r2013) as r2013


into #suma_risk_prestige_nbr
from #risk_prestige_nbr tp1
inner join #risk_prestige_nbr tp2 on tp1.first_mob_InDef>=tp2.first_mob_InDef
group by tp1.first_mob_InDef,tp1.r2007,tp1.r2008,tp1.r2009,tp1.r2010,
tp1.r2011,tp1.r2012,tp1.r2013
order by tp1.first_mob_InDef,tp1.r2007,tp1.r2008,tp1.r2009,tp1.r2010,
tp1.r2011,tp1.r2012,tp1.r2013

Thanks

Foi útil?

Solução

I see that you're using SQL Server, read this link about counting rolling total - Calculate a Running Total in SQL Server.

Fastest way in 2012 - to use sum(...) over (order by ...), in 2008 - use CTE with sequential row_numbers

So, if nulls after largest sum is not critical, you could do (it's not the fastest way, but for fast cte you have to create table with sequential number without gaps).

;with cte as (
  select
     T1.First_mob,
     sum(T2.[r2009]) as [r2009],
     sum(T2.[r2010]) as [r2010],
     sum(T2.[r2011]) as [r2011],
     sum(T2.[r2012]) as [r2012],
     sum(T2.[r2013]) as [r2013]
  from Table1 as T1
     left outer join Table1 as T2 on T2.First_mob <= T1.First_mob
  group by T1.First_mob
)
select
    c1.First_mob,
    c1.[r2009] as [r2009],
    c1.[r2010] as [r2010],
    c1.[r2011] as [r2011],
    c1.[r2012] as [r2012],
    c1.[r2013] as [r2013]
from cte as c1

see sql fiddle example

update the query is a bit weird, but it's because I've made unpivot so I could not to specify all column names everywhere. May be it would be possible to make it more effecient, but now I have this:

;with cte1 as (
  -- unpivoting columns to rows so we could write general queries
   select
       T1.First_mob,
       C.Name, C.Value
   from Table1 as T1
       cross apply (
           select 'r2009', [r2009] union all
           select 'r2010', [r2010] union all
           select 'r2011', [r2011] union all
           select 'r2012', [r2012] union all
           select 'r2013', [r2013]
       ) as C(Name, Value)
), cte2 as (
  -- counting running total
   select
      c1.First_mob, c1.Name, c1.Value, sum(c2.Value) as Total_Value
   from cte1 as c1
       inner join cte1 as c2 on c2.First_mob <= c1.First_mob and c2.Name = c1.Name
   group by c1.First_mob, c1.Name, c1.Value
), cte3 as (
  -- counting total sums (need later)
   select
      c1.Name, sum(c1.Value) as Value
   from cte1 as c1
   group by c1.Name
), cte4 as (
  -- removing all unnecessary values
   select
       c2.First_mob,
       c2.Name,
       case when c3.Value = c2.Total_Value and c2.Value is null then null else c2.Total_Value end as Value
    from cte2 as c2
       inner join cte3 as c3 on c3.Name = c2.Name
)
-- pivoting rows to columns
select
    c4.First_mob,
    max(case when C4.Name = 'r2009' then C4.Value end) as [r2009],
    max(case when C4.Name = 'r2010' then C4.Value end) as [r2010],
    max(case when C4.Name = 'r2011' then C4.Value end) as [r2011],
    max(case when C4.Name = 'r2012' then C4.Value end) as [r2012],
    max(case when C4.Name = 'r2013' then C4.Value end) as [r2013]
from cte4 as c4
group by c4.First_mob

see sql fiddle with example

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top