【问题标题】:Creating hour groups for time series data MySQL为时间序列数据 MySQL 创建小时组
【发布时间】:2014-05-03 07:18:25
【问题描述】:

我有一个 MySQL 数据库,每 15 分钟记录一次数据。为简单起见,我们假设有 2 个字段:

DATETIME Created
Double Value

我想绘制一个图表,该图表需要每小时的开盘、最小值、最大值和收盘值。为此,我需要将 MySQL 查询的结果返回到我的 PHP 以创建 JSON。我想在 MySQL 查询中执行此操作,以便缓存响应。

这是一个问题示例,假设 9 个数据点试图获得 2 小时组:

Creation            Value
2014-03-25 12:15:00 413.17011
2014-03-25 12:00:00 414
2014-03-25 11:45:00 415
2014-03-25 11:30:00 415
2014-03-25 11:15:00 415.5
2014-03-25 11:00:00 415.5
2014-03-25 10:45:00 416
2014-03-25 10:30:00 416
2014-03-25 10:15:00 415.99

我需要:

Hour 1 (11:15:00 to 12:15:00)
Open: 415.5
Close: 413.17011
High: 415.5
Low: 413.17011

Hour 2 (10:15:00 to 11:15:00)
Open: 415.99
Close: 415.5
High: 416
Low: 415.5

当然,这需要在整个 24 小时内重复,这只是一个示例。 非常感谢任何帮助!

这里是示例的当前 MySQL 转储(使用 MySQL 版本 2.6.4-pl3):

-- 
-- Table structure for table `exampleTable`
-- 

CREATE TABLE `exampleTable` (
  `created` datetime NOT NULL,
  `value` double NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

-- 
-- Dumping data for table `exampleTable`
-- 

INSERT INTO `exampleTable` VALUES ('2014-03-25 12:15:00', 413.17011);
INSERT INTO `exampleTable` VALUES ('2014-03-25 12:00:00', 414);
INSERT INTO `exampleTable` VALUES ('2014-03-25 11:45:00', 415);
INSERT INTO `exampleTable` VALUES ('2014-03-25 11:30:00', 415);
INSERT INTO `exampleTable` VALUES ('2014-03-25 11:15:00', 415.5);
INSERT INTO `exampleTable` VALUES ('2014-03-25 11:00:00', 415.5);
INSERT INTO `exampleTable` VALUES ('2014-03-25 10:45:00', 416);
INSERT INTO `exampleTable` VALUES ('2014-03-25 10:30:00', 416);
INSERT INTO `exampleTable` VALUES ('2014-03-25 10:15:00', 415.99);

【问题讨论】:

  • 没有回复让我很担心,所以我会尽可能缩短这个问题。
  • 正如提示:如果可以,您可能希望将日期和时间分成两列(类型为datetime)。这样您就不需要每次都将DATE() 投射到created 上,而是可以使用新的日期列。然后,您也可以向该列添加索引,从而加快查询速度。 See this sqlfiddle for an example.
  • 更好:combined index on both new columns。避免两个文件排序。

标签: php mysql sql json


【解决方案1】:

要正确分组,您可以使用

 FLOOR(( UNIX_TIMESTAMP(myTable.dateCreated) - 900 ) / 3600)

其中 3600 将间隔设置为 1 小时,而 - 900 将偏移量设置为 00:15

由于四个值中的每一个都需要 MIN() 和 MAX,因此您需要将主表连接到自身,但按最小值或最大值分组(基于列)。

最后,您让每个子查询(连接表)计算上面的分组时间,以便您可以使用它来连接它们。这是我想出来的(列名和

SELECT openDate,Open,Close,High,Low 
FROM   (SELECT FLOOR(( UNIX_TIMESTAMP(myTable.dateCreated) - 900 ) / 3600) 
               AS 
                      theHour, 
                      myTable.value AS Open,myTable.dateCreated openDate 
        FROM   myTable 
               JOIN (SELECT value,MIN(dateCreated) AS dateCreated 
                     FROM   myTable 
                     GROUP  BY FLOOR(( UNIX_TIMESTAMP(dateCreated) - 900 ) 
                                     / 3600) 
                    ) AS 
                                    aggTable 
                 ON aggTable.dateCreated = myTable.dateCreated) AS 
       openTable 
       LEFT JOIN (SELECT FLOOR(( UNIX_TIMESTAMP(myTable.dateCreated) - 900 
                               ) / 
                               3600) AS 
       theHour 
       , 
       myTable.value AS Close,myTable.dateCreated closeDate 
       FROM   myTable 
       JOIN (SELECT value,MAX(dateCreated) AS dateCreated 
       FROM   myTable 
       GROUP  BY FLOOR(( UNIX_TIMESTAMP(dateCreated) - 900 ) / 3600) 
       ) AS 
       aggTable 
       ON aggTable.dateCreated = myTable.dateCreated) AS closeTable 
              ON openTable.theHour = closeTable.theHour 
       LEFT JOIN (SELECT 
                                                        FLOOR(( 
                 UNIX_TIMESTAMP(myTable.dateCreated) - 900 ) / 3600) AS 
                   theHour, 
                                                          MAX( 
                                                                  value) 
                 AS High 
                  FROM   myTable 
                  GROUP  BY theHour) AS highTable 
              ON closeTable.theHour = highTable.theHour 
       LEFT JOIN (SELECT 
                                                        FLOOR(( 
                 UNIX_TIMESTAMP(myTable.dateCreated) - 900 ) / 3600) AS 
                   theHour, 
                                                          MIN( 
                                                                  value) 
                 AS Low 
                  FROM   myTable 
                  GROUP  BY theHour) AS lowTable 
              ON highTable.theHour = lowTable.theHour 

【讨论】:

  • 谢谢你 - 看起来不错。我需要一些时间来了解它的确切工作原理,但我会花一些时间来理解它。
  • 重要的是把它想象成一个外部查询和 4 个内部查询,每个内部查询都有一个连接,所以看起来很可怕,但实际上是相同的模式重复结束,只需稍作更改即可获得您想要的顶列值。对不起,这是一团糟。我通过一个美化器运行它,它可能对 SO 来说不是那么美化。
【解决方案2】:

让它工作

你可以试试

SELECT
 DATE(created) AS day,
 HOUR(created) AS hour,
 (
   SELECT Value FROM `table` AS b
   WHERE DATE(a.created) = DATE(b.created)
     AND HOUR(a.created) = HOUR(b.created)
     ORDER BY created ASC LIMIT 1
 ) AS Open,
 (
   SELECT Value FROM `table` AS b
   WHERE DATE(a.created) = DATE(b.created)
     AND HOUR(a.created) = HOUR(b.created)
     ORDER BY created DESC LIMIT 1
 ) AS Close,
 MIN(value) AS Low,
 MAX(value) AS High
FROM `table` AS a
GROUP BY DATE(created), HOUR(created)

这会按 DATE+HOUR 对所有行进行分组,并将 MIN 分别计算为 LowHigh。要查找OpenClose 的第一行和最后一行,SQL 语法中最简单的方法是子选择。它选择与当前行相关的所有行,并按升序或降序对它们进行排序。然后选择第一行。

请考虑这仅按小时分组。而不是

Hour 1 (11:15:00 to 12:15:00)
Hour 2 (10:15:00 to 11:15:00)

这组喜欢

Hour 1 (11:00:00 to 11:59:00)
Hour 2 (10:00:00 to 10:59:00)

如果您想保留 15 分钟的偏移量,您可以在上面的 sql 查询中所有出现 created 时从您创建的时间戳 (created - INTERVAL 15 MINUTE) 中减去它。

我为你创建了a working sqlfiddle

性能

正如提示:如果可以,您可能希望将日期和时间分成两列(类型为datetime)。这样您就不需要每次都在created 上强制转换DATE(),而是可以使用新的日期列。然后,您也可以向这些新列添加组合索引,从而加快查询速度。示例见this sqlfiddle

【讨论】:

  • 这看起来会让我非常接近。我的目标是根据最近的时间间隔来获得它。因此,例如,如果时间现在是 09:36,则应该将 08:30 到 09:30 显示为一组。然后07:30到08:30作为另一个。如果我使用这段代码,也许我可以先计算偏移量。我会玩这个,看看我是否可以改变它,我非常感谢你的帮助(给予支持,如果/当我设法让它工作时,我会接受它)
  • 当然。如果您遇到任何问题,请告诉我们。
  • 感谢 GhostGambler。我更改了我正在测试的表,以使用与您的工作相同的字段名称(值和创建以及表名称为“表”),但我似乎遇到了语法错误。它说:#1064 - 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在第 5 行的“table AS b WHERE DATE(a.created) = DATE(b.created) AND HOUR(a.created)”附近使用正确的语法我将添加数据库表结构作为MySQL转储的问题,可能是我做错了或者解释错了。
  • 请看table is a reserved word。如果您真的想使用它,则需要将其放入反引号中。
  • 在最后一段中查看我对工作 sqlfiddle 的更新答案。
猜你喜欢
  • 2013-06-13
  • 2016-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-27
  • 1970-01-01
  • 2020-12-24
相关资源
最近更新 更多