1

有没有更好的方法来处理这种情况?

我有一个表格,每 5 分钟的“时间”块有几行“速度”。我想取这 5 分钟块中的 12 个块的平均值,以获得每小时的速度。我想出的虚拟方法是计算每个 5 分钟块的总和,然后将它们除以 12。

有没有更好的方法,无论是在编码简单性还是 sql 效率方面?

SELECT (

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
10 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
5 MINUTE) THEN speed ELSE 0 END) + 

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
15 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
10 MINUTE) THEN speed ELSE 0 END) +

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
20 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
15 MINUTE) THEN speed ELSE 0 END) +

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
25 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
20 MINUTE) THEN speed ELSE 0 END) +

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
30 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
25 MINUTE) THEN speed ELSE 0 END) + 

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
35 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
30 MINUTE) THEN speed ELSE 0 END) +

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
40 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
35 MINUTE) THEN speed ELSE 0 END) +

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
45 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
40 MINUTE) THEN speed ELSE 0 END) +

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
50 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
45 MINUTE) THEN speed ELSE 0 END) +

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
55 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
50 MINUTE) THEN speed ELSE 0 END) +

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
60 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
55 MINUTE) THEN speed ELSE 0 END) +

SUM(CASE WHEN time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
65 MINUTE) AND time < DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 
60 MINUTE) THEN speed ELSE 0 END)

)/12
FROM table

谢谢!

4

1 回答 1

1
SELECT AVG(IFNULL(ws.sums, 0))
FROM 
(
  SELECT 1 i union all SELECT 2 union all SELECT 3 union all SELECT 4 union all SELECT 5 union all SELECT 6 union all SELECT 7 union all SELECT 8 union all SELECT 9 union all SELECT 10 union all SELECT 11 union all SELECT 12
) windows
LEFT JOIN
(
  SELECT SUM(speed) sums,
         FLOOR(TIME_TO_SEC(TIMEDIFF(CURRENT_TIMESTAMP, time)) / 300) window
  FROM workers_speeds
  WHERE TIME_TO_SEC(TIMEDIFF(CURRENT_TIMESTAMP, time)) / 60 < 65
  AND TIME_TO_SEC(TIMEDIFF(CURRENT_TIMESTAMP, time)) / 60 > 5
  GROUP BY FLOOR(TIME_TO_SEC(TIMEDIFF(CURRENT_TIMESTAMP, time)) / 300)
) ws on windows.i = ws.window

单击此处在 SQL Fiddle 上查看它的实际效果

解释

首先查看底部的内部查询......我们需要一种简单的方法来识别每个间隔。为此,我使用了该函数来获取列与当前时间TIMEDIFF()之间的差异。time这以 h:m:s 格式返回,因此我将其传递给TIME_TO_SEC()以转换为秒。我们现在可以除以 300(5 分钟内的秒数)并使用该FLOOR()函数向下舍入到最接近的整数。这为我们提供了一种从 1 到 12 的每 5 分钟间隔的 ID,我们可以使用它来GROUP BY. 然后我们将这个 ID 包含在 中,SELECT并为其赋予别名window并添加WHERE&AND子句以确保我们只包含 1 小时的数据,而忽略最近的 5 分钟。

现在看看外部查询...我生成了一个派生表windows,其中包含 12 行虚拟数据,只是整数 1 到 12。然后我们可以LEFT OUTER JOIN将内部查询也作为派生表ws,它允许我们确保始终有 12 行回来。ws.sums如果区间不包含数据,则为 null,但我们可以使用IFNULL()将其转换为 0。

我不完全确定它会完全按照你的要求运行,所以如果你使用它,你应该确保你做了必要的测试,特别是在间隔的边界上。

于 2013-06-01T00:35:33.817 回答