我有这张桌子
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过滤),[上一个]是上一个[当前]值,[当前]是能量值,并且[消耗量]存在-上一个:
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秒。有什么我可以优化的方法,或者还有另一种获取上一行值的方法吗?
答案 0 :(得分:0)
您可以在下面的查询中尝试-
SELECT ApplianceId
,COALESCE(LAG(Energy) OVER (ORDER BY ApplianceId),0) PREVIOUS
,Energy PRESENT
,Energy - COALESCE(LAG(Energy) OVER (ORDER BY ApplianceId),0) FUTURE
FROM T
WHERE ApplicationId = '101'
GROUP BY ApplianceId, Energy
答案 1 :(得分:0)
由于使用的MySQL没有内置的Analytic函数(自v5.6起),因此必须直接在查询中使用用户定义的变量模拟其行为,然后进行构建分阶段进行。
第一步是模拟按ApplianceID划分并按ID排序的分析LAG函数。这需要三个变量。一个跟踪当前分区,一个跟踪先前的能量,最后一个存储下一个先前的能量(即当前能量)。
select ID
, case when @pa != ApplianceID
then @PriorEnergy := 0.0
else @PriorEnergy := @ce
end PriorEnergy
, @pa := ApplianceID ApplianceID
, @ce := energy Energy
from table1
order by ApplianceID, id;
在上面的查询中,case语句处理分区,以便当@pa与当前的ApplianceID不匹配时,将@PriorEnergy变量设置为0.0,否则将@PriorEnergy变量设置为@ce的当前值,该变量保留前一个记录的能量值。在case语句之后,从当前记录更新@pa和@ce以维持状态。上述查询中的排序依据对于确保分区正常工作很重要。
下一步是将上述查询用作较大查询的一部分,以产生最终输出:
select ApplianceID
, PriorEnergy Previous
, Energy Present
, Energy - PriorEnergy Consumption
from (
select ID
, case when @pa != ApplianceID
then @PriorEnergy := 0.0
else @PriorEnergy := @ce
end PriorEnergy
, @pa := ApplianceID ApplianceID
, @ce := Energy Energy
from table1
order by ApplianceID, ID) aq1
order by ApplianceID, id;
您可以在此SQL Fiddle中查看以上两个查询的结果。另外,小提琴中有一个third query,显示了如何在第一个分析查询中计算消耗量,但是要满足使分析处理工作所需的列顺序约束,则投影无法满足您的要求要求。