MySQL – 从前一行减去值,按组
我需要以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
使用MySQLvariables非常好,就像内联程序variables赋值一样。 首先,FROM子句为你“声明”@variables,默认为空白。 然后按照您希望的顺序查询logging。 它通过数据而不是通过可能是时间密集的重复子查询。
对于每行读取,将@lastSN与当前logging的SN进行比较。 如果不同,总是返回0.如果相同,则计算简单差异。 只有在完成比较之后,才能将@lastSN和@lastValue设置为与当前logging的值相等,以便进行下一个logging比较。
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
一个接近通用的解决scheme是通过在连接条件中包含一个相关的子查询来将数据连接到它自己,以查找以前的logging。
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)
这个performance最好,只有一个索引覆盖(SN, Date)
。
这应该做的伎俩:
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;
请参阅SQLFiddle: http ://sqlfiddle.com/#!2/b9eb1/8
你可以像这样连接同一个表的两行:
SELECT this.*, prev.* FROM tbl this INNER JOIN tbl prev ON prev.id = ( SELECT max(t.id) FROM tbl t WHERE t.id < this.id ) WHERE ...
所以你的情况是这样的:
SELECT this.SN, this.Date, this.Value, (this.Value - prev.Value) AS consumption FROM EnergyLog this INNER JOIN EnergyLog prev ON prev.Date = ( SELECT max(t.Date) FROM EnergyLog t WHERE t.Date < this.Date )
你可以请尝试一下下面的查询。
SELECT e1.*, (SELECT Value FROM EnergyLog e2 WHERE e2.sn = e1.sn AND e2.date < e1.date ORDER BY date DESC LIMIT 1)-l.Value consumption FROM EnergyLog e1;