23

我正在尝试按小时使用从我的历史记录表中获取报告。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
4

4 回答 4

36

您现有的查询可以简化为:

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

但是,对于不存在数据的组的处理实际上是业务逻辑的问题,业务逻辑最好放在数据访问层而不是数据库本身:实际上,对于您的应用程序来说,只要一小时就使用零值应该是微不足道的。缺席的。

于 2012-05-03T10:36:52.817 回答
2

修改@eggyal 答案,因为另一个很好的用例是显示日期以及小时数。

假设您需要过去 7 天的 COUNT 条记录,每条记录 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;

SQL 结果

在后端代码的业务逻辑或存储过程中修改它,

INTERVAL 1 DAY

可以产生过去 7 天的查询结果以及当天的名称。

于 2020-09-29T12:17:18.320 回答
1

给定一个包含列tsvalue的表Log,以下将给出过去 24 小时的每小时平均值(假设每个小时至少有一行)。

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

ts可以是时间戳或日期时间列,而value是 AVG() 将接受的任何内容。

于 2016-01-06T10:35:40.897 回答
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;
于 2021-06-30T21:09:43.593 回答