按先前组减去以前的值 - SQL Server

时间:2016-01-08 15:11:19

标签: sql sql-server sql-server-2008

之前已经问过这个问题并且特别为MySQL做了很好的回答,但是我非常感谢你们帮助我们为SQL Server翻译这个问题。之前的帖子已关闭,我不想重新打开它们,因为它们已经很老了。

以下是要查询的数据集,以及查询解决方案的必需输出。下面是这里发布的优秀MySql解决方案(SQL best way to subtract a value of the previous row in the query?)。我的问题是如何使用SQL Server中的变量完成相同的结果。如果这是一个新手问题我很抱歉,但我是SQL Server中的变量新手,并且在尝试根据SQL Server中的变量的MSDN文档转换为SQL Server时失败了。

感谢您的帮助!

select
      EL.SN,
      EL.Date,
      EL.EL.Value,
      if( @lastSN = EL.SN, EL.Value - @lastValue, 0000.00 ) as Consumption,
      @lastSN := EL.SN,
      @lastValue := EL.Value
   from
      EnergyLog EL,
      ( select @lastSN := 0,
               @lastValue := 0 ) SQLVars
   order by
      EL.SN,
      EL.Date

    

我需要通过SN号将消耗值基于前一个消耗值。 这是我的数据:

TABLE EnergyLog

SN     Date                 Value
2380   2012-10-30 00:15:51  21.01
2380   2012-10-31 00:31:03  22.04
2380   2012-11-01 00:16:02  22.65
2380   2012-11-02 00:15:32  23.11
20100  2012-10-30 00:15:38  35.21
20100  2012-10-31 00:15:48  37.07
20100  2012-11-01 00:15:49  38.17
20100  2012-11-02 00:15:19  38.97
20103  2012-10-30 10:27:34  57.98
20103  2012-10-31 12:24:42  60.83

这是我需要的结果:

SN      Date                 Value  consumption
2380    2012-10-30 00:15:51  21.01  0
2380    2012-10-31 00:31:03  22.04  1.03
2380    2012-11-01 00:16:02  22.65  0.61
2380    2012-11-02 00:15:32  23.11  0.46
20100   2012-10-30 00:15:38  35.21  0
20100   2012-10-31 00:15:48  37.07  1.86
20100   2012-11-01 00:15:49  38.17  1.1
20100   2012-11-02 00:15:19  38.97  0.8
20103   2012-10-30 10:27:34  57.98  0
20103   2012-10-31 12:24:42  60.83  2.85

3 个答案:

答案 0 :(得分:2)

通过使用CTE,您可以获得订购的数据,然后选择上一条记录。

WITH PREVCTE AS (
SELECT  *, 
        ROW_NUMBER() OVER (PARTITION BY SN ORDER BY MyDate) [RowNum] 
FROM @myTable
)
SELECT A.SN, 
       A.MyDate, 
       A.[Value], 
       A.[Value] - COALESCE(B.[Value], A.[Value]) [Consumption]
FROM PREVCTE A LEFT OUTER JOIN PREVCTE B 
    ON   A.RowNum - 1 = B.RowNum AND  
         A.SN = B.SN 

<强> SQL Fiddle Demo

答案 1 :(得分:0)

我之前的解决方案计算了运行总计。在shawnt00发表评论并回顾你提供的例子后,我发现事实并非如此。这应该使解决方案更容易。我相信以下内容适用于SQL 2008,虽然我目前还没有方便的2008盒子来测试它。

;WITH CTE_Ordered AS
(
    SELECT
        sn,
        [date],
        value,
        ROW_NUMBER() OVER(PARTITION BY sn ORDER BY [date]) AS row_num
    FROM
        dbo.EnergyLog
)
SELECT
    T1.sn,
    T1.[date],
    T1.value,
    T1.value - COALESCE(T2.value, 0) AS consumption
FROM
    CTE_Ordered T1
LEFT OUTER JOIN CTE_Ordered T2 ON
    T2.sn = T1.sn AND
    T2.row_num = T1.row_num - 1
ORDER BY
    T1.sn,
    T1.row_num

答案 2 :(得分:0)

我相信您正在寻找相邻日期之间的差异。这是一种方式。

select
    SN, Date, Value,
    Value - (
        select coalesce(max(Value), 0) from EnergyLog el2
        where el2.SN = el.SN and el2.Date < el.Date
        group by el2.SN
    ) as consumption
from EnergyLog el

如果你总能假设时间间隔是上限的,那么你可以通过缩小回顾窗口的大小来提升性能。这也取决于索引。

select
    SN, Date, Value,
    Value - (
        select coalesce(max(Value), 0) from EnergyLog el2
        where el2.SN = el.SN
            and el2.Date > dateadd(hour, -48, el.Date) /* max gap 48 hrs? */
            and el2.Date < el.Date
        group by el2.SN
    ) as consumption
from EnergyLog el

编辑:根据您在下面关于序列号的评论:

select
    SN, Date, Value,
    Value - (
        select coalesce(max(Value), 0) from EnergyLog el2
        where el2.SN = el.SN and el2.SeqNo = el.SeqNo - 1
        group by el2.SN
    ) as consumption
from EnergyLog el

您当然可以使用外连接而不是标量子查询。当然,如果您已经有序列号,那么您不需要row_number()来生成它们。