此问题与我前一段时间发布的问题有关,可在此处找到:Update values of database with values that are already in DB。
我遇到以下情况:存储来自不同传感器的数据的表格(我总共有8个传感器)。该表的每一行都具有以下结构:
SensorID --- TimestampMS --- RawData --- Data
因此,例如,对于名为TEMPSensor1的温度传感器,我有以下内容:
TEMPSensor1 --- 1000 --- 200 --- 2
TEMPSensor1 --- 2000 --- 220 --- 2.2
等等,每个传感器(总共我8个)。我在阅读数据时遇到了一些问题,并且有些行数据“不正确”。确切地说,当rawdata字段为65535时,我应该更新该特定行。而我想要做的是将下一个值(及时)放到“损坏的数据”中。所以,如果我们有这个:
TEMPSensor1 --- 1000 --- 200 --- 2
TEMPSensor1 --- 2000 --- 220 --- 2.2
TEMPSensor1 --- 3000 --- 65535 --- 655.35
TEMPSensor1 --- 4000 --- 240 --- 2.4
执行更新后,表格的内容应更改为:
TEMPSensor1 --- 1000 --- 200 --- 2
TEMPSensor1 --- 2000 --- 220 --- 2.2
TEMPSensor1 --- 3000 --- 240 --- 2.4
TEMPSensor1 --- 4000 --- 240 --- 2.4
我最终做了以下事情:
UPDATE externalsensor es1
INNER JOIN externalsensor es2 ON es1.sensorid = es2.sensorid AND (es2.timestampms - es1.timestampms) > 60000 AND (es2.timestampms - es1.timestampms) < 120000 AND es1.rawdata <> 65535
SET es1.rawdata = es2.rawdata, es1.data = es2.data
WHERE es1.rawdata = 65535
因为我知道传感器的两次读取之间有60000到120000毫秒。但是,如果我有两个“损坏的”读数,那将无效。任何人都可以建议一种更有效地做到这一点的方法,不使用子查询选择,但加入?我的想法是让一个JOIN在它的时间戳之后为你提供该传感器的所有可能值,然后得到第一个,但我不知道如何限制JOIN结果。
欣赏。
答案 0 :(得分:2)
这是一个没有相关子查询的解决方案,但是有一个三角形连接(不确定哪个更糟):
UPDATE externalsensor bad
INNER JOIN (
SELECT
es1.SensorID,
es1.TimestampMS,
MIN(es2.TimestampMS) AS NextGoodTimestamp
FROM externalsensor es1
INNER JOIN externalsensor es2
ON es1.SensorID = es2.SensorID AND
es1.TimestampMS < es2.TimestampMS
WHERE es1.RawData = 65535
AND es2.RawData <> 65535
GROUP BY
es1.SensorID,
es1.TimestampMS
) link ON bad.SensorID = link.SensorID AND
bad.TimestampMS = link.TimestampMS
INNER JOIN externalsensor good
ON link.SensorID = good.SensorID AND
link.NextGoodTimestamp = good.TimestampMS
SET
bad.RawData = good.RawData,
bad.Data = good.Data
假设时间戳在单个传感器组中是唯一的。
答案 1 :(得分:1)
由于您不想使用上一个问题的Dems解决方案,这里是JOIN的“解决方案”:
UPDATE myTable m
JOIN myTable n
ON m.SensorID = n.SensorID
AND n.RawData <> 65535
AND m.TimestampMS < n.TimestampMS
JOIN myTable q
ON n.SensorID = q.SensorID
AND q.RawData <> 65535
AND n.TimestampMS <= q.TimestampMS
SET
m.RawData = n.RawData,
m.Data = n.Data
WHERE
m.RawData = 65535
;
修改
我上面的查询错了,错了。它似乎在我的测试数据库中工作,但逻辑是有缺陷的。我将在下面解释。
为什么上面的查询工作正常但是出错了:
首先,为什么这是错误的。
因为它不会为每个(sensorID,bad timestamp)组合返回一行,但会返回很多行。如果m
(m.TimestampMS
)是我们想要查找的错误时间戳,它将返回该不良时间戳的所有组合以及稍后的好时间戳n
和q
{{1 }}。如果找到这些n.TimestampMS <= q.TimestampMS
时间戳的最小值,那将是一个正确的查询。
现在,为什么它在我的测试数据库中实际可行?
我认为这是因为MySQL在使用n
时有很多选项(行),它只使用第一个选项。但幸运的是,我以增加的时间戳顺序添加了测试行,因此它们在数据库中以该顺序保存,并且(再次)幸运的是,这就是查询计划的安排方式(我推测)。
即使这个查询也适用于我的测试db:
SET ...
虽然出于同样的原因存在缺陷。
答案 2 :(得分:1)
一种完全不同的方法,使用贯穿整个表的过程(按每个传感器的降序时间顺序):
DELIMITER $$
CREATE PROCEDURE updateMyTable()
BEGIN
SET @dummy := -9999 ;
SET @dummy2 := -9999 ;
SET @sensor := -999 ;
UPDATE myTable m
JOIN
( SELECT n.SensorID
, n.TimestampMS
, @d := (n.RawData = 65535) AND (@sensor = n.SensorID) AS problem
, @dummy := IF(@d, @dummy, n.RawData) as goodRawData
, @dummy2 := IF(@d, @dummy2, n.Data) as goodData
, @sensor := n.SensorID AS previous
FROM myTable n
ORDER BY n.SensorID
, n.TimeStampMS DESC
) AS upd
ON m.SensorID = upd.SensorID
AND m.TimeStampMS = upd.TimeStampMS
SET m.RawData = upd.goodRawData
, m.Data = upd.goodData
WHERE upd.problem
;
END$$
DELIMITER ;