【问题标题】:How to subtract previous value in a column with calculation of other column on SQL server如何通过 SQL Server 上的其他列的计算减去列中的先前值
【发布时间】:2017-03-13 19:54:47
【问题描述】:

我需要如下所示的表格。如您所见,mgt_year、tot_dflt_mgt 和 to_accum_mgt 列。在 2016 的年份列中,值为 20,累积值为 600。我想要的是当我这样做时

(to_accum_mgt - tot_dflt_mgt) 

我希望在上一行中显示此计算结果,如下表所示。然后这个计算结果,即 580 用于减去 9,例如 2015 年的 (580 - 9) 等所有尾随年份。感谢@mathguy,我已经在excel和Oracle中做到了这一点,但是如何在SQL Server中实现这个结果。我曾尝试使用此 SQL 服务器,但它无法正常工作。

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

我的桌子:

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

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:
    select *,
    (sum(TOT_ACCUM_MGT) over()) -
    (sum(TOT_DFLT_MGT ) over (order by TOT_DFLT_MGT )) as somecolname
    from
    table
    

    【讨论】:

    • 谢谢@TheGameiswar。但是您要减去 TOT_ACCUM_MGT - TOT_accum_mgt。我也试过了,但没有用。
    • 你好@TheGameiswar。我已经编辑了这个问题。请再次检查它可能会让您更好地了解我在寻找什么。再次感谢您给我的解决方案,但它在 SQL Server 中不起作用。
    • 请解释你的输出
    • 如您在上表中所见,我需要在结尾处执行此操作 (to_accum_mgt - tot_dflt_mgt) 。其输出将进入tot_accum_mgt 的前一行,并将用于减去该行的tot_dflt_mgt 的值,反之亦然,直到输出表中显示的line_seg 窗口。
    【解决方案2】:

    把 Row_number() 和自己加入到 (a.ID = b.ID) 和 (a.row_num = b.row_num - 1) 上的前一行 或者 你可以使用 lag() 函数

    【讨论】:

      【解决方案3】:

      请尝试以下查询。我假设您使用的是 2012+ 版本的 SQL Server。如果不是,请将 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 的当前 computed 值中减去之前的 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)
      

      【讨论】:

      • 谢谢@shiblu 会试试这个并让你知道。
      猜你喜欢
      • 2017-07-23
      • 2021-05-01
      • 1970-01-01
      • 2020-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      相关资源
      最近更新 更多