MySQL - 从上一行减去值,分组依据

use*_*142 32 mysql sql

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

表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
Run Code Online (Sandbox Code Playgroud)

这是我需要的结果:

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
Run Code Online (Sandbox Code Playgroud)

DRa*_*app 73

使用MySQL变量非常棒,就像内联程序变量赋值一样.首先,FROM子句为您"声明"@变量,默认为空.然后按照您希望的顺序查询记录.它通过数据而不是通过重复的子查询进行单次传递,这可能是时间密集的.

对于读取的每一行,将@lastSN与当前记录的SN进行比较.如果不同,则始终返回0.如果相同,则计算简单差异.只有完成比较后,将@lastSN和@lastValue设置为等于当前记录的值,以便进行下一次记录比较.

select
      EL.SN,
      EL.Date,
      EL.Value, --remove duplicate alias
      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
Run Code Online (Sandbox Code Playgroud)

  • 我希望我能多次投票. (8认同)
  • @Yeti,不,如果您不想在FINAL结果中看到这些列,只需将此查询再包起一个级别,并仅拉出您想要的列(因此没有at-place-holder列). (6认同)
  • 是否可以在不实际将其返回结果的情况下,将其分配给@lastSN:= EL.SN,@lastValue:= EL.Value`?(我知道您不必使用它) (2认同)

bid*_*ifx 14

这应该做的伎俩:

SELECT l.sn,
       l.date, 
       l.value,
       l.value - (SELECT value 
                  FROM energylog x
                  WHERE x.date < l.date
                  AND x.sn = l.sn
                  ORDER BY date DESC
                  LIMIT 1) consumption
FROM energylog l;
Run Code Online (Sandbox Code Playgroud)

请参阅SQLFiddle:http://sqlfiddle.com/#!2/b9eb1/8


Mat*_*lie 13

一种近乎通用的解决方案是通过在连接条件中包含相关的子查询来将数据连接到自身,以查找先前的记录...

SELECT
  ThisLog.*,
  COALESCE(ThisLog.Value - PrevLog.Value, 0) AS consumption
FROM
  EnergyLog    AS ThisLog
LEFT JOIN
  EnergyLog    AS PrevLog
    ON  PrevLog.SN   = ThisLog.SN
    AND PrevLog.Date = (SELECT MAX(Date)
                          FROM EnergyLog
                         WHERE SN   = ThisLog.SN
                           AND Date < ThisLog.Date)
Run Code Online (Sandbox Code Playgroud)

一个索引涵盖两者,这表现最佳(SN, Date).

  • 如果您不能或不想使用@variables,这是一个快速的解决方案. (2认同)