【问题标题】:sql cumulative sum with null values under specific conditions特定条件下带有空值的sql累积和
【发布时间】:2013-08-08 08:27:56
【问题描述】:

我需要创建具有累积总和的表: - 如果行中没有任何值,则 value 和 null 的总和为 null

我想从中创建累积总和的初始表如下所示:

+--------------------+---------------+------+-----+---------+-------+
| 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   | 
+--------------------+---------------+------+-----+---------+-------+

我想要获取的表格看起来像

+--------------------+---------------+------+-----+---------+-------+
| 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   | 
+--------------------+---------------+------+-----+---------+-------+

我的累积和的 sql 代码如下:

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

谢谢

【问题讨论】:

  • 什么数据库系统?什么版本? sql 标签用于标准语言,但对某些功能的支持因产品而异。
  • 我使用的是 sqlserver 2008

标签: sql sql-server sql-server-2008 null cumulative-sum


【解决方案1】:

我看到您使用的是 SQL Server,请阅读此链接以了解如何计算滚动总数 - Calculate a Running Total in SQL Server

2012 年最快的方式 - 在 2008 年使用 sum(...) over (order by ...) - 使用带有连续 row_numbers 的 CTE

因此,如果最大总和后的空值并不重要,您可以这样做(这不是最快的方法,但对于快速 cte,您必须创建具有连续编号且没有间隙的表)。

;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

参见sql fiddle 示例

update 查询有点奇怪,但这是因为我进行了 unpivot,所以我无法在任何地方指定所有列名。也许有可能让它更有效,但现在我有了这个:

;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

参见sql fiddle 示例

【讨论】:

  • 我使用的是 sqlserver 2008
  • 您的 First_mob 列是否有间隙或者是连续的?
  • 我的 first_mob 列没有空白值作为空值,但有时没有完全线性增量,例如它可以采用以下值:1,2,4,5,6,9....
  • 5 和 8 之后的空值绝对关键吗?
  • 是的,在 5 和 8 之后我应该有空值,因为在第一个表中,在 5 和 8 之后的 5 和 8 列 r2011 为 5 和 r2013 为 8 中没有其他数字(只有空值)跨度>
猜你喜欢
  • 1970-01-01
  • 2015-11-19
  • 2018-08-09
  • 2022-01-27
  • 1970-01-01
  • 1970-01-01
  • 2020-09-30
  • 2016-05-28
  • 1970-01-01
相关资源
最近更新 更多