我正在将温度记录到sqlite db,传感器每40秒发送一次〜6读数突发,以确保收到一个读数。通过将唯一属性添加到日期字段,我消除了大多数重复项。但是,有时时钟在猝发期间滴答1秒,因此我的记录相距约1秒。我想每40秒一次仅保留一次读数。我如何找到(并删除)这些记录?
insDate id temp humidity
2019-07-08 11:34:07 176 41.36 70.0
2019-07-08 11:34:46 176 41.36 70.0
2019-07-08 11:34:47 176 41.36 70.0
2019-07-08 11:35:26 176 41.36 70.0
2019-07-08 11:36:05 176 41.36 70.0
2019-07-08 11:36:06 176 41.36 70.0
2019-07-08 11:36:45 176 41.36 70.0
答案 0 :(得分:0)
假设每个相邻的40秒块始终总是正好有6个读数,那么不一定有6个读数组的开始和结束。我们可以尝试按40秒的块汇总读数,然后仅对每个块取MIN
读数:
SELECT
ts % 40 AS block,
MIN(reading) AS reading
FROM yourTable
GROUP BY
ts % 40
ORDER BY
ts % 40;
之所以可行,是因为假设我们选择的最小值实际上属于“上一个”块,因为我们错误地猜测了边界。然后,该移位也将出现在下一个块中,然后在下一个块中,因此最后没有关系。
此答案假设时间读数在称为ts
的列中,并且包含从纪元以来的秒数。
答案 1 :(得分:0)
为避免注释中讨论的问题,其中数学时间窗口(使用模运算符)可能会任意中断/拆分同一突发的读数,而我们可以检查相邻记录以获取连续读数之间的时间延迟。问题的详细内容意味着与突发之间的延迟(约40秒)相比,同一突发记录中的读取可能会在很短的时间内(几秒钟内)发生。因此,要使每个猝发读取一次读数,请仅选择对下一条记录有较长延迟的记录,大约2到40秒之间……我有点随意选择10。
幸运的是,sqlite支持窗口功能,该功能允许使用基本SQL查询比较相邻的行,而无需在SQL之外编写任何脚本。
WITH sensorExt AS (
SELECT *,
strftime('%s', insDate) AS tsec --Convert to seconds since 1970-01-01 00:00:00
FROM sensor )
SELECT *
FROM -- Must use subquery in order to apply WHERE conditions to window function results
(SELECT sensorExt.*,
(lead(tsec) OVER (ORDER BY insDate ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING))
- tsec as postspan -- Calculate difference between following row seconds
FROM sensorExt
ORDER BY sensorExt.insDate) AS sensorExt2
WHERE
-- Only keep rows which are at end of "burst" with large delay to next record
-- coalesce() is called to handle/include the null value of the last record.
coalesce(postspan, 11) > 10
注1 :我更喜欢在可能的情况下使用公用表表达式(CTE; WITH子句)代替子查询,但是似乎存在一个错误CTE中的>“窗口函数” (即OVER子句),因此我不得不恢复为子查询。否则,我将使用一系列CTE表来代替混合结构。
注释2 :使用标准的聚合SQL查询,也可以在没有窗口函数的情况下完成此操作,但是我认为至少需要3个嵌套子查询集才能获得相邻行之间的差异