如何通过计算SQL Server上的其他列来减去列中的先前值

时间:2017-03-13 09:37:24

标签: sql sql-server

我需要一个表格,如下所示。您可以看到mgt_yeartot_dflt_mgtto_accum_mgt列。在年度栏中 2016 20 且累计值 600 。我想要的是当我做的时候

(to_accum_mgt - tot_dflt_mgt) 

我希望这个计算结果在前一行中,如下表所示。然后,此计算结果,即 580 用于减去 9 ,如2015年的(580 - 9),依此类推所有过去年份。感谢@mathguy,我已经在excel和Oracle中完成了这个,但是如何在SQL服务器中实现这个结果。我曾尝试使用此 SQL服务器,但它无效。

请原谅我糟糕的英语和菜鸟格式。

我的表t:

line_seg    MGT_YEAR TOT_DFLT_MGT TOT_ACCUM_MGT
---------   -------- ------------ ------------
   A           2013           10   
   A           2014           15   
   A           2015            9   
   A           2016           20          600
   B           2013           10   
   B           2014           15   
   B           2015            8   
   B           2016           20          500

Oracle解决方案:

select mgt_year, tot_dflt_mgt,
       max(tot_accum_mgt) over () - 
         nvl( sum(tot_dflt_mgt) over 
                   (order by mgt_year 
                          rows between 1 following and unbounded following)
            , 0 ) as tot_accum_mgt
from t;    

但我无法在SQL Server中使用此功能。

必需的输出

line_seg    MGT_YEAR TOT_DFLT_MGT TOT_ACCUM_MGT
---------   -------- ------------ ------------
   A           2013           10          556
   A           2014           15          471 
   A           2015            9          580
   A           2016           20          600
   B           2013           12          457
   B           2014           15          472
   B           2015            8          480
   B           2016           20          500

3 个答案:

答案 0 :(得分:1)

select *,
(sum(TOT_ACCUM_MGT) over()) -
(sum(TOT_DFLT_MGT ) over (order by TOT_DFLT_MGT )) as somecolname
from
table

答案 1 :(得分:0)

把Row_number()和self连接到(a.ID = b.ID)上的前一行和(a.row_num = b.row_num - 1) 要么 您可以使用lag()函数

答案 2 :(得分:0)

请尝试以下查询。我假设您使用的是2012+版本的SQL Server。如果没有,请将FIRST_VALUE更改为SUM -

+------------+----------+--------------+---------------+
|  line_seg  | mgt_year | tot_dflt_mgt | tot_accum_mgt |
+------------+----------+--------------+---------------+
| A          |     2016 |           20 | 600           |
| A          |     2015 |            9 | NULL          |
| A          |     2014 |           15 | NULL          |
| A          |     2013 |           10 | NULL          |
| B          |     2016 |           20 | 500           |
| B          |     2015 |            8 | NULL          |
| B          |     2014 |           15 | NULL          |
| B          |     2013 |           12 | NULL          |
+------------+----------+--------------+---------------+

首先,我必须将表格按日期的降序排序 -

+------------+----------+--------------+---------------+------------+----------+--------------+---------------+
|  line_seg  | mgt_year | tot_dflt_mgt | tot_accum_mgt |  line_seg  | mgt_year | tot_dflt_mgt | tot_accum_mgt |
+------------+----------+--------------+---------------+------------+----------+--------------+---------------+
| A          |     2013 |           10 | NULL          | A          | 2014     | 15           | NULL          |
| A          |     2014 |           15 | NULL          | A          | 2015     | 9            | NULL          |
| A          |     2015 |            9 | NULL          | A          | 2016     | 20           | 600           |
| A          |     2016 |           20 | 600           | NULL       | NULL     | NULL         | NULL          |
| B          |     2013 |           12 | NULL          | B          | 2014     | 15           | NULL          |
| B          |     2014 |           15 | NULL          | B          | 2015     | 8            | NULL          |
| B          |     2015 |            8 | NULL          | B          | 2016     | 20           | 500           |
| B          |     2016 |           20 | 500           | NULL       | NULL     | NULL         | NULL          |
+------------+----------+--------------+---------------+------------+----------+--------------+---------------+

然后,我所要做的就是从最近一年的 tot_accum_mgt 中减去PREVIOUS总计 tot_dflt_mgt 。这相当于从 tot_accum_mgt 的当前计算值中减去之前的 tot_dflt_mgt 。要使用上一年的字段,请使用LEFT JOIN自行加入表。导致下表 -

ISNULL(SUM(t2.[tot_dflt_mgt]) OVER(PARTITION BY t2.[line_seg] ORDER BY t2.mgt_year DESC), 0) AS tot_accum_mgt

LEFT join子句中的 AND t2.mgt_year = t1.mgt_year + 1 过滤器可以获得前一行值的技巧。现在我所要做的就是计算前一行的运行总数(t2)。另外,从任何内容中减去 NULL 将导致 NULL 。所以 ISNULL 用零替换任何 NULL

FIRST_VALUE(t1.tot_accum_mgt) OVER(PARTITION BY t1.[line_seg] ORDER BY t1.mgt_year DESC)

现在,由于我们之前的运行总计为tot_dflt_mgt,我们所要做的就是删除最新的(最大 mgt_year tot_accum_mgt 。我们通过使用 FIRST_VALUE 函数来实现。我猜也可以使用SUM。

undefined