在我的表中,我有字段(名为id,binary和timestamp)从门上的传感器集获取数据,当门被打开时,它将二进制值发送为1,带有时间戳和自己的id。当它关闭时,它将二进制值发送为0以及时间戳和id。并且,它发送连续数据,而不是像它打开时只发送数据并停止,而是继续发送具有相同值的二进制和id除了时间戳之外的数据。例如,昨天当门被打开2秒时,它发送了这样的数据:
------------------------
id---binary---timestamp
------------------------
XX-----1------2014-12-29 21:09:08
XX-----1------2014-12-29 21:09:08
XX-----1------2014-12-29 21:09:08
XX-----1------2014-12-29 21:09:08
XX-----1------2014-12-29 21:09:08
XX-----1------2014-12-29 21:09:09
XX-----1------2014-12-29 21:09:09
XX-----1------2014-12-29 21:09:09
XX-----1------2014-12-29 21:09:09
XX-----1------2014-12-29 21:09:09
XX-----0------2014-12-29 21:09:10
XX-----0------2014-12-29 21:09:10
XX-----0------2014-12-29 21:09:10
........................................so on..
上面的图片可以全天找到门打开的次数为1值,其余时间为0值。
现在,我想计算每天在图表中显示门打开多长时间的总持续时间。但问题是,我不知道从上面的数据如何使用时间戳计算持续时间。我知道我可以使用TIMEDIFF()和TIME_TO_SEC()函数进行计算,但那只有我有一个开始时间和结束时间 - 在我的情况下,我没有。
我还想到了选择二进制= 1的所有值并将它们加在一起的想法,但那不是实际持续时间,导致我的传感器有时会发送相同数据5次/秒,有时会发送3次/秒。如果它被固定,总是发送5data / sec然后我可以总结总和除以5来找到单秒,但它不是那样的。
有人有想法解决这个问题吗?
提前致谢.. :))
答案 0 :(得分:1)
好的,有多种可能的答案。
如果您确定,表格中的每一秒都有一个条目,您可以这样做:
select
id, `binary`,
sec_to_time(count(distinct `timestamp`))
from
t
where `timestamp` between concat(curdate(), ' 00:00:00') and concat(curdate(), ' 23:59:59')
/*you could also do
where date(timestamp) = curdate()
but having a function on a column does not allow MySQL to use an index*/
group by id, `binary`
请注意,使用保留关键字作为列名称并不是一个好主意,就像二进制和时间戳这样的情况一样。它们不仅几乎没有描述性,而且你也总是不得不使用反引号
使用distinct
,您只能获得该列中的唯一条目。使用count
计算秒数,然后使用sec_to_time
将其转换为更易读的格式。
您可以通过在unique
列上添加(id, binary, timestamp)
索引而不是insert ...
执行insert ignore ...
来实现此操作。这样,表中每秒只能输入一个条目。
如果你不能假设你每秒都有一个条目,那么它会变得更复杂。 Best会有一个额外的列,表示列binary
中的值更改。您可以使用如下示例中的变量来模拟它,但它可能没有良好的性能。
SELECT `binary`, SEC_TO_TIME(SUM(secondsOnOffPerGroup))
FROM (
SELECT
id, `binary`, valueChangeGroup, TIMESTAMPDIFF(SECOND, MIN(`timestamp`), MAX(`timestamp`)) + 1 as secondsOnOffPerGroup
FROM (
SELECT
t.*,
@valueChangeGroup := IF(@prevB != `binary`, @valueChangeGroup + 1, @valueChangeGroup) as valueChangeGroup,
@prevB := `binary`
FROM
t
, (SELECT @prevB := null, @valueChangeGroup := 0) var_init_subquery_alias
WHERE
`timestamp` between concat(curdate(), ' 00:00:00') and concat(curdate(), ' 23:59:59')
ORDER BY id, `timestamp`
) sq
GROUP BY id, `binary`, valueChangeGroup
) sq2
GROUP BY `binary`
我们在这里做的是先按id和时间戳排序。然后,如果当前行的值与前一行不同,则增加变量。在外部查询中,我们将此变量分组并获取每个组的最小和最大时间戳,因此我们可以计算差异。我在那里添加+ 1
,因为当门打开或关闭一秒钟时,差异显然为0.如果它打开或关闭2秒,则差异为1.在最外层的查询中,我们分组binary
并将秒数相加。
答案 1 :(得分:1)
如果你想检查门每天打开的持续时间,那么为什么你说你没有开始和结束时间?
您有边界条件,例如:
Start timestamp - 2014-12-29 00:00:01
End timestamp - 2014-12-29 00:00:00
现在接近这样:
1) Set count=0 and totalOpenTime=0
2) if the row fetched have binary '1' set count = count + 1 then fetch next row
3) if in next row binary is '0' then add count to totalOpenTime and set count to 0
but if in next row binary is '1' then set count = count + 1 and fetch next row
4) do this until timestamp < End timestamp
希望有所帮助:)