Mysql 如何按工作日计算每小时4周移动平均值?

Mysql 如何按工作日计算每小时4周移动平均值?,mysql,Mysql,给定一个带有datetime列的表,我想得到每个结果的每小时4周移动平均条目数,以及每星期几 例如,在10月1日和10月13日之间,我想得到一个结果,显示按小时和星期几分组的行数的4周滚动平均值 到目前为止,我得到的是4周的小时总数,但不是滚动总数: SELECT DAYOFWEEK(start_time) as DOW, date_format( start_time, '%H' ) as 'HOUR', count( * ) as 'count' FROM mytab

给定一个带有datetime列的表,我想得到每个结果的每小时4周移动平均条目数,以及每星期几

例如,在10月1日和10月13日之间,我想得到一个结果,显示按小时和星期几分组的行数的4周滚动平均值

到目前为止,我得到的是4周的小时总数,但不是滚动总数:

SELECT 
   DAYOFWEEK(start_time) as DOW, 
   date_format( start_time, '%H' ) as 'HOUR',
   count( * ) as 'count' 
FROM mytable 
WHERE start_time >='2017-08-01' and start_time <= '2017-08-29' 
GROUP BY DAYOFWEEK(start_time),date_format( start_time, '%H' )
选择
DAYOFWEEK(开始时间)作为道琼斯指数,
日期格式(开始时间,“%H”)为“小时”,
计数(*)为“计数”
从mytable

其中,开始时间>='2017-08-01'和开始时间,这是一种经过部分测试的方法

它使用日期参数来确保where子句的一致性。其他参数也用于控制每小时的存储桶(我在有限的测试中使用了3)和周数(我在测试中使用了0,因为我有一组非常小的行)

第一个子查询用于生成“范围”,当连接到源行时,将这些行放入每个“滚动n小时范围”。这些范围是通过使用日期\格式输出YYYYMMDDHH(字符串)来定义的,然后数据也被强制使用相同的字符串格式进行连接,因此如果在大型表上使用,这可能会导致性能问题(是的,不是sargable,我也不喜欢)

这一解决方案可能会奏效

架构设置:

查询

set @start_time := '2017-08-02';
set @num_hrs    := 4; -- controls length of rolling period e.g. 4 hours each
set @num_weeks  := 4; -- controls the date date

set @end_time   := date_add(@start_time, INTERVAL ((7 * @num_weeks)+1) DAY);

SELECT
       DOW
     , hour_of_day 
     , COUNT(*) period_count
     , (COUNT(*) * 1.0) / @num_hrs rolling_av
FROM (
    ## build a set of ranges in YYYYMMDDHH format differing by the wanted number of hours
    SELECT 
          id
       ,  DATE_FORMAT(date_add(start_time, INTERVAL (@num_hrs*-1) HOUR), '%Y%m%d%H') as range_start
       ,  DATE_FORMAT(start_time, '%Y%m%d%H') as range_end
    FROM mytable
    WHERE start_time >= @start_time and start_time < @end_time
    ) R
INNER JOIN (
    SELECT
           start_time
         , DAYOFWEEK(start_time) as DOW 
         , date_format(start_time, '%H' ) as hour_of_day
    FROM MyTable
    WHERE start_time >= @start_time and start_time < @end_time
    ) T ON DATE_FORMAT(T.start_time, '%Y%m%d%H') >= R.range_start
                    AND DATE_FORMAT(T.start_time, '%Y%m%d%H') <= R.range_end
GROUP BY 
       DOW, hour_of_day
ORDER BY 
       DOW, hour_of_day
;

请注意,介于
之间的
不适合日期/时间范围。您的where子句与此等价:
start_time>='2017-08-01 00:00:00'和start_time='2017-08-01 00:00:00'和start_time<'2017-08-30 00:00:00'
(这将为您提供8月29日的所有时间,但从8月30日起不提供任何内容)抱歉,不需要额外的
00:00
。只是为了解释。看一看关于同一主题的第一个问题:非常感谢!!!这已经非常有用了。我真正想要的是只提供一个日期范围,并按照您所描述的或多或少地返回结果。此外,我对3hr bucket在这里发生的事情有点困惑。我在我的示例数据中连续几天每小时只创建了3行,这样我就不会超过sqlfidle的小数据余量。由于将num_hrs设置为3,因此允许我获得可预测的结果。你所要做的就是
设置@num\u hrs:=4;设置@num_weeks:=4应该是上帝让我们走。当然,你需要对它进行测试,直到你满意为止。AVG不应该出现在代码中,它是不需要的(我怀疑是复制/粘贴错误)2。我可能误解了这个问题。代码所做的是从每小时中扣除@num_hrs,得到每小时的“移动平均值”。如果你真的想要每小时4周的移动平均数,那么小时数应该是(4*7*24)“那么结束时间可以是一个不同的日期?”什么结束时间?您所需要的只是提供的参数。(开始日期+周数)=日期范围否。这将计算日期范围的结束。跟踪@end_time所在位置的查询。这就是where子句,这就是它所做的一切。它是<代码> @ NUMYHRS< /代码>,你需要改变,然后得到4周(4×7×24),请考虑你每小时要求这些平均值,所以精确度必须是小时。
set @start_time := '2017-08-02';
set @num_hrs    := 4; -- controls length of rolling period e.g. 4 hours each
set @num_weeks  := 4; -- controls the date date

set @end_time   := date_add(@start_time, INTERVAL ((7 * @num_weeks)+1) DAY);

SELECT
       DOW
     , hour_of_day 
     , COUNT(*) period_count
     , (COUNT(*) * 1.0) / @num_hrs rolling_av
FROM (
    ## build a set of ranges in YYYYMMDDHH format differing by the wanted number of hours
    SELECT 
          id
       ,  DATE_FORMAT(date_add(start_time, INTERVAL (@num_hrs*-1) HOUR), '%Y%m%d%H') as range_start
       ,  DATE_FORMAT(start_time, '%Y%m%d%H') as range_end
    FROM mytable
    WHERE start_time >= @start_time and start_time < @end_time
    ) R
INNER JOIN (
    SELECT
           start_time
         , DAYOFWEEK(start_time) as DOW 
         , date_format(start_time, '%H' ) as hour_of_day
    FROM MyTable
    WHERE start_time >= @start_time and start_time < @end_time
    ) T ON DATE_FORMAT(T.start_time, '%Y%m%d%H') >= R.range_start
                    AND DATE_FORMAT(T.start_time, '%Y%m%d%H') <= R.range_end
GROUP BY 
       DOW, hour_of_day
ORDER BY 
       DOW, hour_of_day
;
| DOW | hour_of_day | period_count | rolling_av |
|-----|-------------|--------------|------------|
|   4 |          00 |           36 |         12 |
|   4 |          01 |           36 |         12 |
|   4 |          02 |           36 |         12 |
|   4 |          03 |           36 |         12 |
|   4 |          04 |           36 |         12 |
|   4 |          05 |           36 |         12 |
|   4 |          06 |           36 |         12 |
|   4 |          07 |           36 |         12 |
|   4 |          08 |           36 |         12 |
|   4 |          09 |           36 |         12 |
|   4 |          10 |           36 |         12 |
|   4 |          11 |           36 |         12 |
|   4 |          12 |           36 |         12 |
|   4 |          13 |           36 |         12 |
|   4 |          14 |           36 |         12 |
|   4 |          15 |           36 |         12 |
|   4 |          16 |           36 |         12 |
|   4 |          17 |           36 |         12 |
|   4 |          18 |           36 |         12 |
|   4 |          19 |           36 |         12 |
|   4 |          20 |           36 |         12 |
|   4 |          21 |           27 |          9 |
|   4 |          22 |           18 |          6 |
|   4 |          23 |            9 |          3 |