【问题标题】:SELECT / GROUP BY - segments of time (10 seconds, 30 seconds, etc)SELECT / GROUP BY - 时间段(10 秒、30 秒等)
【发布时间】:2011-03-06 09:49:36
【问题描述】:

我有一个表 (MySQL),它每 n 秒捕获一次样本。该表有很多列,但最重要的是两列:一个时间戳(TIMESTAMP 类型)和一个计数(INT 类型)。

我想做的是获取计数列在一段时间内的总和和平均值。例如,我每 2 秒记录一次样本,但我想要所有样本在 10 秒或 30 秒窗口中的所有样本的计数列的总和。

以下是数据示例:

+------------------+------------------+ |时间戳 |计数 | +------------------+------------------+ | 2010-06-15 23:35:28 | 1 | | 2010-06-15 23:35:30 | 1 | | 2010-06-15 23:35:30 | 1 | | 2010-06-15 23:35:30 |第942章 | 2010-06-15 23:35:30 | 180 | | 2010-06-15 23:35:30 | 4 | | 2010-06-15 23:35:30 | 52 | | 2010-06-15 23:35:30 | 12 | | 2010-06-15 23:35:30 | 1 | | 2010-06-15 23:35:30 | 1 | | 2010-06-15 23:35:33 | 1468 | | 2010-06-15 23:35:33 | 247 | | 2010-06-15 23:35:33 | 1 | | 2010-06-15 23:35:33 | 81 | | 2010-06-15 23:35:33 | 16 | | 2010-06-15 23:35:35 | 1828 | | 2010-06-15 23:35:35 | 214 | | 2010-06-15 23:35:35 | 75 | | 2010-06-15 23:35:35 | 8 | | 2010-06-15 23:35:37 | 1799 | | 2010-06-15 23:35:37 | 24 | | 2010-06-15 23:35:37 | 11 | | 2010-06-15 23:35:37 | 2 | | 2010-06-15 23:35:40 |第575章 | 2010-06-15 23:35:40 | 1 | | 2010-06-17 10:39:35 | 2 | | 2010-06-17 10:39:35 | 2 | | 2010-06-17 10:39:35 | 1 | | 2010-06-17 10:39:35 | 2 | | 2010-06-17 10:39:35 | 1 | | 2010-06-17 10:39:40 | 35 | | 2010-06-17 10:39:40 | 19 | | 2010-06-17 10:39:40 | 37 | | 2010-06-17 10:39:42 | 64 | | 2010-06-17 10:39:42 | 3 | | 2010-06-17 10:39:42 | 31 | | 2010-06-17 10:39:42 | 7 | | 2010-06-17 10:39:42 | 246 | +------------------+------------------+

我想要的输出(基于上面的数据)应该是这样的:

+------------------+------------------+ | 2010-06-15 23:35:00 | 1 | # 这是 00 - 30 秒范围的总和 | 2010-06-15 23:35:30 | 7544 | # 这是 30 - 60 秒范围的总和 | 2010-06-17 10:39:35 | 450 | # 这是 30 - 60 秒范围的总和 +------------------+------------------+

我使用 GROUP BY 按秒或按分钟收集这些数字,但我似乎无法弄清楚使亚分钟或秒范围 GROUP BY 命令正常工作的语法。

我将主要使用此查询将数据从该表中抽取到另一个表中。

谢谢!

【问题讨论】:

    标签: mysql sql select group-by


    【解决方案1】:

    很奇怪,但在这里使用解决方案:

    Average of data for every 5 minutes in the given times

    我们可以建议如下:

    select convert(
                  (min(dt_record) div 50)*50 - 20*((convert(min(dt_record), 
                   datetime) div 50) mod 2), datetime)  as dt, 
           avg(1das4hrz) 
    from `meteor-m2_msgi`
    where dt_record>='2016-11-13 05:00:00'
           and dt_record < '2016-11-14 00:00:00' 
    group by convert(dt_record, datetime) div 50;
    
    
    select (
    convert(
    min(dt_record), datetime) div 50)*50 - 20*(
    (convert(min(dt_record), datetime) div 50) mod 2
    ) as dt,
    avg(column) from `your_table`
    where dt_record>='2016-11-13 05:00:00'
    and dt_record < '2016-11-14 00:00:00'
    group by convert(dt_record, datetime) div 50;
    

    50 是因为 NORMAL 分钟的 1/2 有 30 秒,而“整数日期格式”假设我们除以 50

    【讨论】:

      【解决方案2】:

      另一种解决方案。

      要在您喜欢的任何时间间隔内进行平均,您可以将 dt 转换为时间戳,并按您的时间间隔(示例中为 7 秒)按模数分组。

      select FROM_UNIXTIME(
          UNIX_TIMESTAMP(dt_record) - UNIX_TIMESTAMP(dt_record) mod 7
      ) as dt, avg(1das4hrz) from `meteor-m2_msgi`
      where dt_record>='2016-11-13 05:00:00'
      and dt_record < '2016-11-13 05:02:00'
      group by FROM_UNIXTIME(
          UNIX_TIMESTAMP(dt_record) - UNIX_TIMESTAMP(dt_record) mod 7);
      

      为了展示它是如何工作的,我准备了一个请求,显示计算。

      select dt_record, minute(dt_record) as mm, SECOND(dt_record) as ss,
      UNIX_TIMESTAMP(dt_record) as uxt, UNIX_TIMESTAMP(dt_record) mod 7 as ux7,
      FROM_UNIXTIME(
          UNIX_TIMESTAMP(dt_record) - UNIX_TIMESTAMP(dt_record) mod 7) as dtsub,
      column from `yourtable` where dt_record>='2016-11-13 05:00:00'
      and dt_record < '2016-11-13 05:02:00';
      
      +---------------------+--------------------+
      | dt                  | avg(column)        |
      +---------------------+--------------------+
      | 2016-11-13 04:59:43 |  25434.85714285714 |
      | 2016-11-13 05:00:42 |  5700.728813559322 |
      | 2016-11-13 05:01:41 |  950.1016949152543 |
      | 2016-11-13 05:02:40 |  4671.220338983051 |
      | 2016-11-13 05:03:39 | 25468.728813559323 |
      | 2016-11-13 05:04:38 |  43883.52542372881 |
      | 2016-11-13 05:05:37 | 24589.338983050846 |
      +---------------------+--------------------+
      
      
      +---------------------+-----+-----+------------+------+---------------------+----------+
      | dt_record           | mm  | ss  | uxt        | ux7  | dtsub               | column   |
      +---------------------+------+-----+------------+------+---------------------+----------+
      | 2016-11-13 05:00:00 |   0 |   0 | 1479002400 |    1 | 2016-11-13 04:59:59 |    36137 |
      | 2016-11-13 05:00:01 |   0 |   1 | 1479002401 |    2 | 2016-11-13 04:59:59 |    36137 |
      | 2016-11-13 05:00:02 |   0 |   2 | 1479002402 |    3 | 2016-11-13 04:59:59 |    36137 |
      | 2016-11-13 05:00:03 |   0 |   3 | 1479002403 |    4 | 2016-11-13 04:59:59 |    34911 |     
      | 2016-11-13 05:00:04 |   0 |   4 | 1479002404 |    5 | 2016-11-13 04:59:59 |    34911 |
      | 2016-11-13 05:00:05 |   0 |   5 | 1479002405 |    6 | 2016-11-13 04:59:59 |    34911 |
      | 2016-11-13 05:00:06 |   0 |   6 | 1479002406 |    0 | 2016-11-13 05:00:06 |    33726 |
      | 2016-11-13 05:00:07 |   0 |   7 | 1479002407 |    1 | 2016-11-13 05:00:06 |    32581 |
      | 2016-11-13 05:00:08 |   0 |   8 | 1479002408 |    2 | 2016-11-13 05:00:06 |    32581 |
      | 2016-11-13 05:00:09 |   0 |   9 | 1479002409 |    3 | 2016-11-13 05:00:06 |    31475 |
      +---------------------+-----+-----+------------+------+---------------------+----------+
      

      谁能更快地提出建议?

      【讨论】:

        【解决方案3】:

        我在我的项目中尝试了 Hammerite 的解决方案,但在系列中缺少样本的情况下效果不佳。这是一个查询示例,它应该从 metric_table 中选择时间戳 (ts)、用户名和平均度量值,并按 27 分钟的时间间隔对结果进行分组:

        select 
            min(ts), 
            user_name, 
            sum(measure) / 27
        from metric_table 
        where 
            ts between date_sub('2015-03-17 00:00:00', INTERVAL 2160 MINUTE) and '2015-03-17 00:00:00' 
        
        group by unix_timestamp(ts) div 1620, user_name 
        order by ts, user_name
        ;
        

        注意:27 分钟(选择)= 1620 秒(分组),2160 分钟 = 3 天(这是时间范围)

        当我针对不定期记录样本的时间序列运行此查询时(换句话说:对于任何给定的时间戳,无法保证找到所有用户名的度量值),结果未根据间隔标记(不是每 27 分钟放置一次)。我怀疑这是由于 min(ts) 在某些组中返回的时间戳大于预期的下限 (ts0 + i*interval)。我将以前的查询修改为这个:

        select 
            from_unixtime(unix_timestamp(ts) - unix_timestamp(ts) mod 1620) as ts1, 
            user_name, 
            sum(measure) / 27
        from metric_table
        where 
            ts between date_sub('2015-03-17 00:00:00', INTERVAL 2160 MINUTE) and '2015-03-17 00:00:00' 
        
        group by ts1, user_name 
        order by ts1, user_name
        ;
        

        即使样本丢失,它也能正常工作。我认为这是因为一旦将时间数学移动到选择它就保证 ts1 将与时间步长对齐。

        【讨论】:

        • 感谢您提出这个问题,帮了我很多忙!
        • 好东西!我现在需要的只是一种方法,让它在那个时间桶中没有样本时记录一个“零”行......
        • @DanielRhodes 有没有想过这个?
        【解决方案4】:

        GROUP BY UNIX_TIMESTAMP(time_stamp) DIV 30

        或者说出于某种原因您想以 20 秒的间隔将它们分组为 DIV 20 等。要更改 GROUP BY 值之间的边界,您可以使用

        GROUP BY (UNIX_TIMESTAMP(time_stamp) + r) DIV 30

        其中r 是小于 30 的文字非负整数。所以

        GROUP BY (UNIX_TIMESTAMP(time_stamp) + 5) DIV 30

        应该给你 hh:mm:05 和 hh:mm:35 之间以及 hh:mm:35 和 hh:mm+1:05 之间的总和。

        【讨论】:

        • 完美!这正是我需要的!非常感谢!
        • 请完整查询。我无法使用此解决方案归档 OP 结果
        猜你喜欢
        • 2010-11-26
        • 2022-01-24
        • 2011-09-26
        • 1970-01-01
        • 1970-01-01
        • 2021-10-27
        • 1970-01-01
        相关资源
        最近更新 更多