我正在尝试按小时使用情况从历史记录表中获取报告。 history
表是;
CREATE TABLE IF NOT EXISTS `history` (
`history_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned NOT NULL DEFAULT '0',
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`history_id`),
KEY `user_id` (`user_id`),
KEY `created` (`created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
我希望按HOUR
和COUNT
分组给定日期范围内的所有记录。
Hours | Usage
------------------------------------
00:00-01:00 | 5
01:00-02:00 | 9
02:00-03:00 | 0 (or NULL)
03:00-04:00 | 20
...
...
...
22:00-23:00 | 11
23:00-00:00 | 1
我使用了类似这样的查询,但它并没有显示所有小时数。
SELECT
CASE
WHEN HOUR(created) BETWEEN 0 AND 1 THEN '00:00 - 01:00'
WHEN HOUR(created) BETWEEN 1 AND 2 THEN '01:00 - 02:00'
WHEN HOUR(created) BETWEEN 2 AND 3 THEN '02:00 - 03:00'
WHEN HOUR(created) BETWEEN 3 AND 4 THEN '03:00 - 04:00'
WHEN HOUR(created) BETWEEN 4 AND 5 THEN '04:00 - 05:00'
WHEN HOUR(created) BETWEEN 5 AND 6 THEN '05:00 - 06:00'
WHEN HOUR(created) BETWEEN 6 AND 7 THEN '06:00 - 07:00'
WHEN HOUR(created) BETWEEN 7 AND 8 THEN '07:00 - 08:00'
WHEN HOUR(created) BETWEEN 8 AND 9 THEN '08:00 - 09:00'
WHEN HOUR(created) BETWEEN 9 AND 10 THEN '09:00 - 10:00'
WHEN HOUR(created) BETWEEN 10 AND 11 THEN '10:00 - 11:00'
WHEN HOUR(created) BETWEEN 11 AND 12 THEN '11:00 - 12:00'
WHEN HOUR(created) BETWEEN 12 AND 13 THEN '12:00 - 13:00'
WHEN HOUR(created) BETWEEN 13 AND 14 THEN '13:00 - 14:00'
WHEN HOUR(created) BETWEEN 14 AND 15 THEN '14:00 - 15:00'
WHEN HOUR(created) BETWEEN 15 AND 16 THEN '15:00 - 16:00'
WHEN HOUR(created) BETWEEN 16 AND 17 THEN '16:00 - 17:00'
WHEN HOUR(created) BETWEEN 17 AND 18 THEN '17:00 - 18:00'
WHEN HOUR(created) BETWEEN 18 AND 19 THEN '18:00 - 19:00'
WHEN HOUR(created) BETWEEN 19 AND 20 THEN '19:00 - 20:00'
WHEN HOUR(created) BETWEEN 20 AND 21 THEN '20:00 - 21:00'
WHEN HOUR(created) BETWEEN 21 AND 22 THEN '21:00 - 23:00'
WHEN HOUR(created) BETWEEN 22 AND 23 THEN '22:00 - 23:00'
WHEN HOUR(created) BETWEEN 23 AND 24 THEN '23:00 - 00:00'
END AS `Hours`,
COUNT(*) AS `usage`
FROM history
WHERE (created BETWEEN '2012-02-07' AND NOW())
GROUP BY
CASE
WHEN HOUR(created) BETWEEN 0 AND 1 THEN 1
WHEN HOUR(created) BETWEEN 1 AND 2 THEN 2
WHEN HOUR(created) BETWEEN 2 AND 3 THEN 3
WHEN HOUR(created) BETWEEN 3 AND 4 THEN 4
WHEN HOUR(created) BETWEEN 4 AND 5 THEN 5
WHEN HOUR(created) BETWEEN 5 AND 6 THEN 6
WHEN HOUR(created) BETWEEN 6 AND 7 THEN 7
WHEN HOUR(created) BETWEEN 7 AND 8 THEN 8
WHEN HOUR(created) BETWEEN 8 AND 9 THEN 9
WHEN HOUR(created) BETWEEN 9 AND 10 THEN 10
WHEN HOUR(created) BETWEEN 10 AND 11 THEN 11
WHEN HOUR(created) BETWEEN 11 AND 12 THEN 12
WHEN HOUR(created) BETWEEN 12 AND 13 THEN 13
WHEN HOUR(created) BETWEEN 13 AND 14 THEN 14
WHEN HOUR(created) BETWEEN 14 AND 15 THEN 15
WHEN HOUR(created) BETWEEN 15 AND 16 THEN 16
WHEN HOUR(created) BETWEEN 16 AND 17 THEN 17
WHEN HOUR(created) BETWEEN 17 AND 18 THEN 18
WHEN HOUR(created) BETWEEN 18 AND 19 THEN 19
WHEN HOUR(created) BETWEEN 19 AND 20 THEN 20
WHEN HOUR(created) BETWEEN 20 AND 21 THEN 21
WHEN HOUR(created) BETWEEN 21 AND 22 THEN 22
WHEN HOUR(created) BETWEEN 22 AND 23 THEN 23
WHEN HOUR(created) BETWEEN 23 AND 24 THEN 24
END
仅在有任何记录时显示。
Hours | Usage
------------------------------------
00:00-01:00 | 5
01:00-02:00 | 9
23:00-00:00 | 1
答案 0 :(得分:25)
您现有的查询可以简化为:
SELECT CONCAT(HOUR(created), ':00-', HOUR(created)+1, ':00') AS Hours
, COUNT(*) AS `usage`
FROM history
WHERE created BETWEEN '2012-02-07' AND NOW()
GROUP BY HOUR(created)
要显示每小时,包括那些没有数据的小时,您需要使用包含您想要数据的所有小时数的表进行外连接。您可以使用UNION
:
SELECT CONCAT(Hour, ':00-', Hour+1, ':00') AS Hours
, COUNT(created) AS `usage`
FROM history
RIGHT JOIN (
SELECT 0 AS Hour
UNION ALL SELECT 1 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
UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18
UNION ALL SELECT 19 UNION ALL SELECT 20 UNION ALL SELECT 21
UNION ALL SELECT 22 UNION ALL SELECT 23
) AS AllHours ON HOUR(created) = Hour
WHERE created BETWEEN '2012-02-07' AND NOW() OR created IS NULL
GROUP BY Hour
ORDER BY Hour
然而,对没有数据存在的组的处理实际上是业务逻辑的问题,这些逻辑最好放在数据访问层而不是数据库本身:事实上,应用程序每次使用零值都应该是微不足道的一个小时不存在。
答案 1 :(得分:1)
修改@eggyal答案,因为另一个好用例是同时显示日期和小时。
假设您需要COUNT个过去7天的记录,每个记录为24小时。
SELECT
dayname(date_sub(curdate(), INTERVAL 1 DAY)) AS Day,
CONCAT(Hour, ':00-', Hour+1, ':00') AS Hour,
COUNT(created) AS `usage`
FROM
history
RIGHT JOIN
(
SELECT 0 AS Hour
UNION ALL SELECT 1 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
UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18
UNION ALL SELECT 19 UNION ALL SELECT 20 UNION ALL SELECT 21
UNION ALL SELECT 22 UNION ALL SELECT 23
)
AS totalhours
ON HOUR(created) = HOUR
AND DATE(created) = date_sub(curdate(), INTERVAL 1 DAY)
OR created IS NULL
GROUP BY
Hour
ORDER BY
Hour;
在后端代码的业务逻辑或存储过程中进行修改,
INTERVAL 1 DAY
可以产生过去7天的查询结果以及日期名称。
答案 2 :(得分:0)
Given a table Log with columns ts and value, the following will give the hourly average for the last 24 hours (assuming each hour has at least one row).
SELECT
FROM_UNIXTIME( TRUNCATE( UNIX_TIMESTAMP( `ts` )/3600, 0 ) * 3600 ) as h,
AVG( `value` ) as v,
COUNT( * ) as q
FROM
Log
GROUP BY
h
ORDER BY
h desc
LIMIT
24
The column ts can be a timestamp or datetime column while value is anything that AVG() will accept.
答案 3 :(得分:0)
根据 Prashanth 的回应,我收到了关于 Hour 模棱两可的警告(Percona 5.7)。另外,我没有按正确的顺序得到结果。以下为我解决了这些问题,并且对 GROUP BY 和 ORDER BY 子句更加清楚:
SELECT
dayname(date_sub(curdate(), INTERVAL 1 DAY)) AS Day,
CONCAT(Hour, ':00-', Hour+1, ':00') AS Hour,
COUNT(created_at) AS `total`
FROM logtable
RIGHT JOIN
(
SELECT 0 AS Hour
UNION ALL SELECT 1 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
UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18
UNION ALL SELECT 19 UNION ALL SELECT 20 UNION ALL SELECT 21
UNION ALL SELECT 22 UNION ALL SELECT 23
)
AS totalhours
ON ( HOUR(created_at) = HOUR
AND DATE(created_at) = date_sub(curdate(), INTERVAL 1 DAY) )
OR created_at IS NULL
GROUP BY
CONCAT(Hour, ':00-', Hour+1, ':00')
ORDER BY
totalhours.Hour;