[英]How to subtract previous value in a column with calculation of other column on SQL server
我需要一张下表,如下所示。 如您所见, mgt_year
, tot_dflt_mgt
和to_accum_mgt
列。 在年份列中,其2016年的值为20 ,累计值为600 。 我想要的是当我做的时候
(to_accum_mgt - tot_dflt_mgt)
我希望此计算结果在上一行中,如下表所示。 然后,此计算结果(即580 )用于减去2015年的9,例如(580-9) ,以此类推。 感谢@mathguy
,我已经在excel和Oracle中完成了此@mathguy
,但是如何在SQL Server中实现此结果。 我试图使用此SQL Server,但无法正常工作。
请原谅我的英语和noob格式不正确。
我的桌子
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
select *,
(sum(TOT_ACCUM_MGT) over()) -
(sum(TOT_DFLT_MGT ) over (order by TOT_DFLT_MGT )) as somecolname
from
table
放入Row_number()并将其与(a.ID = b.ID)和(a.row_num = b.row_num-1)上的上一行自行连接,或者可以使用lag()函数
请尝试以下查询。 我假设您使用的是SQL Server 2012+版本。 如果不是,请将FIRST_VALUE更改为SUM-
SELECT t1.line_seg, t1.mgt_year, t1.[tot_dflt_mgt]
, FIRST_VALUE(t1.tot_accum_mgt) OVER(PARTITION BY t1.[line_seg] ORDER BY t1.mgt_year DESC)
- ISNULL(SUM(t2.[tot_dflt_mgt]) OVER(PARTITION BY t2.[line_seg] ORDER BY t2.mgt_year DESC), 0) AS tot_accum_mgt
FROM [dbo].[t] AS t1
LEFT JOIN [dbo].[t] AS t2 ON (t2.line_seg = t1.line_seg AND t2.mgt_year = t1.mgt_year + 1)
ORDER BY t1.line_seg, t1.mgt_year ASC;
首先,我必须想象该表按日期的降序排序-
+------------+----------+--------------+---------------+
| 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 |
+------------+----------+--------------+---------------+
然后,我要做的就是从最近一年的tot_accum_mgt中减去之前的tot_dflt_mgt总计 。 这等效于从tot_accum_mgt的当前计算值中减去先前的tot_dflt_mgt。要使用上一年的字段, 则将 LEFT JOIN用于自联接表。 得出下表-
+------------+----------+--------------+---------------+------------+----------+--------------+---------------+
| 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 |
+------------+----------+--------------+---------------+------------+----------+--------------+---------------+
LEFT连接子句中的AND t2.mgt_year = t1.mgt_year + 1过滤器可完成获取前一行值的技巧。 现在,我要做的就是计算前几行(t2)的运行总计。 同样,从任何东西中减去NULL将导致NULL 。 因此ISNULL用零代替任何NULL 。
ISNULL(SUM(t2.[tot_dflt_mgt]) OVER(PARTITION BY t2.[line_seg] ORDER BY t2.mgt_year DESC), 0) AS tot_accum_mgt
现在,由于我们拥有先前的tot_dflt_mgt总计,因此我们要做的就是删除最新的(最大的mgt_year ) tot_accum_mgt 。 我们通过使用FIRST_VALUE函数获得该信息。 我猜也可以使用SUM。
FIRST_VALUE(t1.tot_accum_mgt) OVER(PARTITION BY t1.[line_seg] ORDER BY t1.mgt_year DESC)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.