使用时间戳计算总时间

时间:2014-12-30 08:33:56

标签: mysql

在我的表中,我有字段(名为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来找到单秒,但它不是那样的。

有人有想法解决这个问题吗?

提前致谢.. :))

2 个答案:

答案 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

希望有所帮助:)