【问题标题】:calculating total time using timestamp使用时间戳计算总时间
【发布时间】:2014-12-30 08:33:55
【问题描述】:

在我的表中,我有字段(名为 id、二进制和时间戳)从门上的传感器获取数据,当门打开时,它发送二进制值作为 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() 函数进行计算,但这仅在我有开始时间和结束时间时——在我的情况下,我没有。

我还想到了一个想法,即选择 binary=1 的所有值并将它们加在一起,但这不是实时持续时间,因为我的传感器有时会以 5 次/秒的速度发送相同的数据,有时会以 3 次/秒的速度发送。如果解决了始终发送 5 个数据/秒的问题,那么我可以将总数相加并除以 5 以找到单秒,但事实并非如此。

谁有办法解决这个问题?

提前谢谢..:)

【问题讨论】:

    标签: mysql


    【解决方案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 ...。这样,您每秒只能在表中获得一个条目。

    如果您不能假设每秒都有一个条目,那么它会变得更加复杂。最好有一个附加列,指示列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。在最外面的查询中,我们按@987654333分组@ 并计算秒数。

    • sqlfiddle 中实时查看它的工作情况

    【讨论】:

    • 实际上我每秒钟都有几个条目。现在它的 40 条目/秒。所以有几个具有相同二进制值和时间戳的数据,意味着有很多重复。在这种情况下,你不认为结果会不准确吗?但是,是的,您的代码似乎非常接近,也许这就是我想要的。让我更深入地检查一下...感谢您的回复。
    • 每秒有多少条目并不重要(性能方面除外)。在第一个解决方案中,重要的是一天中的每一秒都有一个条目。在第二种解决方案中,这无关紧要,每秒是否有多个条目也无关紧要。有了关于唯一索引和插入忽略的提示,我只想解决性能问题。
    【解决方案2】:

    如果你想检查每天开门的时间,那你为什么说你没有开始和结束时间?

    你有边界条件,例如:

    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
    

    希望对你有帮助:)

    【讨论】:

    • 好吧,我不确定如何为您的观点编写准确的代码 (3)。但我不清楚我将如何设置边界的问题。在这里,我只提供了几秒钟的数据,因此定义开始和结束时间戳似乎很容易。但是那里有数百万的数据,我只能设置一天的边界,例如 2014-12-29 00:00:00 到 2014-12-29 23:59:59。传感器现在每秒发送 40 个数据。所以一天总共有 40x60x60x24 的数据。那我怎么能逐行检查呢?对不起,但如果你不介意你能解释一下吗?感谢您的回复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    • 2022-01-16
    • 2020-09-24
    • 1970-01-01
    • 2015-05-01
    相关资源
    最近更新 更多