我有一个MySQL数据库,每15分钟记录一次数据。为简单起见,我们假设有两个字段:
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);
答案 0 :(得分: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分别计算为Low
或High
。要查找Open
和Close
的第一行和最后一行,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 - INTERVAL 15 MINUTE
时,从你创建的时间戳(created
)中减去它。
我为你创建了a working sqlfiddle。
同样提示:如果可以,您可能希望将日期和时间分成两列(类型为date
和time
)。这样,您不需要每次都在DATE()
上投射created
,而是可以使用新的日期列。然后,您也可以为这些新列添加组合索引,从而加快查询速度。有关示例,请参阅this sqlfiddle。
答案 1 :(得分: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