我有这张table
Id | ApplianceId | Energy
1 | 101 | 0.6
2 | 103 | 1.5
3 | 107 | 1.3
4 | 101 | 1.0
5 | 101 | 1.5
6 | 103 | 2.1
我想在查询中显示的是(通过applianceid过滤),[previous]是前一个[present]值,[present]是能量值,[consumption]是present-previous:
ApplianceId | Previous | Present | Consumption
101 | 0 | 0.6 | 0.6
101 | 0.6 | 1.0 | 0.4
101 | 1.0 | 1.5 | 0.5
我已经有一个工作查询,但它太慢了(原因是在获取上一个值时)。
SELECT
ApplianceId,
COALESCE((SELECT MAX(Energy) FROM table WHERE
id < t.id AND ApplicationId = '101' ORDER BY id DESC LIMIT 1),0) As Previous,
Energy AS Present,
ROUND(MAX(m.wh_total) - (SELECT Previous),2) AS Consumption
FROM
table t
WHERE ApplicationId = '101'
ORDER BY Id
我在10万条记录上查询这个,运行大约需要30秒。如果删除获取前一行的部分,只需要0.4秒。是否有任何方法可以优化或有其他方法获得前一行的值?
2条答案
按热度按时间huwehgph1#
你可以试试下面的查询-
kkih6yb82#
由于您使用的mysql没有内置的分析函数(从v5.6开始),因此您必须在查询中使用用户定义的变量来模拟它们的行为,并分阶段进行构建。
第一步是模拟由applianceid划分并按id排序的解析滞后函数,该函数包含三个变量。一个用来跟踪当前分区,一个用来跟踪先前的能量,最后一个用来存储下一个先前的能量(即当前能量)。
在上面的查询中,case语句处理分区,这样当@pa与当前applianceid不匹配时,@priorenergy变量被设置为0.0,否则,@priorenergy变量被设置为@ce的当前值,该变量保存来自上一条记录的能量值。在case语句之后,@pa和@ce从当前记录更新为保持状态。上述查询中的order by对于确保分区正常工作非常重要。
下一步是将上述查询用作更大查询的一部分,以生成最终输出:
您可以在这个sql fiddle中看到上面两个查询的结果。此外,fiddle中还有第三个查询,显示如何作为第一个分析查询的一部分来计算消耗量,但是如果不考虑使分析处理工作所需的列顺序约束,则投影不满足您的要求。