使用SQL按每小时统计数据的方法

在数据分析和报表生成中,按小时统计数据是一个常见的需求。无论是监控系统的运行状态,还是分析用户行为模式,小时级别的数据统计都能提供细致且有价值的信息。

需要知道

时间戳与时间格式

在SQL数据库中,时间数据通常以时间戳的形式存储。时间戳是一个表示特定时间点的整数,通常以毫秒或秒为单位。例如,1521008160000就是一个13位的毫秒级时间戳。

时间函数

MySQL提供了一系列时间函数,用于处理和转换时间数据。常用的函数包括:

  • FROM_UNIXTIME():将Unix时间戳转换为日期时间格式。
  • DATE_FORMAT():根据指定的格式显示日期时间数据。
  • HOUR():从时间值中提取小时部分。

按小时统计数据的实现方法

简单的时间转换与分组

假设我们有一个名为dspreport的表,其中包含一个名为hourtime的列,存储的是毫秒级时间戳。我们可以使用以下SQL查询按小时分组统计数据:

sql 复制代码
SELECT 
    FROM_UNIXTIME(hourtime / 1000, '%Y-%m-%d %H') AS hour,
    COUNT(*) AS count
FROM 
    dspreport
GROUP BY 
    FROM_UNIXTIME(hourtime / 1000, '%Y-%m-%d %H');

这个查询首先将毫秒级时间戳转换为秒级时间戳,然后使用FROM_UNIXTIME()函数将其转换为YYYY-MM-DD HH格式的字符串,最后按这个字符串分组并计数。

使用DATE_FORMAT()函数

另一种方法是使用DATE_FORMAT()函数,直接对时间戳进行格式化:

sql 复制代码
SELECT 
    DATE_FORMAT(FROM_UNIXTIME(hourtime / 1000), '%Y-%m-%d %H') AS hour,
    COUNT(*) AS count
FROM 
    dspreport
GROUP BY 
    DATE_FORMAT(FROM_UNIXTIME(hourtime / 1000), '%Y-%m-%d %H');

这种方法与第一种方法类似,但DATE_FORMAT()函数提供了更多的格式化选项,更加灵活。

示例

示例一:查询某个时间段内各个小时的访客人数

首先我们需要一个表来存储访客的访问记录。这个表至少需要包含两个字段:visit_time(访问时间)和ip(访客的IP地址)。例如:

sql 复制代码
CREATE TABLE visitor_logs (
  id INT AUTO_INCREMENT PRIMARY KEY,
  ip VARCHAR(50) NOT NULL,
  visit_time DATETIME NOT NULL
);

接着写出按小时查询访客人数的sql:

go 复制代码
SELECT
  HOUR(visit_time) AS hour,
  COUNT(DISTINCT ip) AS visitor_count
FROM
  visitor_logs
WHERE
  visit_time BETWEEN '开始时间' AND '结束时间'
GROUP BY
  HOUR(visit_time);

如果想要不区分是否为独立访客,只想要得到被访问次数的话,可以将COUNT (DISTINCT ip)改为COUNT(*)

需要注意的是:如果使用的是 PostgreSQL ,可能会因为 PostgreSQL 没有内置的 HOUR 函数而收到错误提示: "function hour(timestamp without time zone) does not exist",可以换成 EXTRACT 函数来获取时间戳中的小时部分

示例二:查询每小时内新建对话次数

部分数据库表如下图所示:

我们按照上面的方法,编写sql来查询每小时内新建对话数:

sql 复制代码
SELECT EXTRACT(HOUR FROM created_at) as hour, COUNT(*) as conversation_count 
FROM conversations 
WHERE created_at BETWEEN '2024-11-19 07:03:28.09' AND '2024-11-26 07:03:28.09' 
GROUP BY EXTRACT(HOUR FROM created_at) 
ORDER BY hour

运行该sql得出以下结果:

但是与数据库中的数据做比较后,很容易发现问题:

其中在不同日期但同一时间的数据被归纳到了一起。

为了解决这个问题,我们需要在原SQL上做一些"升级"

sql 复制代码
SELECT DATE(created_at) as date, EXTRACT(HOUR FROM created_at) as hour, COUNT(*) as conversation_count 
FROM conversations 
WHERE created_at BETWEEN '2024-11-19 07:03:28.09' AND '2024-11-26 07:03:28.09' 
GROUP BY DATE(created_at), EXTRACT(HOUR FROM created_at) 
ORDER BY date, hour

之后我们再创建一个结构体来接收得到的数据,就可以啦

go 复制代码
type ChartData []struct {
	Date  time.Time `gorm:"column:date"`
	Hour  int       `gorm:"column:hour"`
	Count int       `gorm:"column:count"`
}

sql := "SELECT DATE(created_at) as date, EXTRACT(HOUR FROM created_at) as hour, COUNT(*) as conversation_count FROM conversations WHERE created_at BETWEEN '2024-11-19 07:03:28.09' AND '2024-11-26 07:03:28.09' GROUP BY DATE(created_at),EXTRACT(HOUR FROM created_at) ORDER BY date, hour"
datas := ChartData{}
err := db.Raw(sql,StartTime,EndTime)//这里StartTime和EndTime可以是提前定义或从前端获取等

最终我们可以得到一个这样的东西:

go 复制代码
[{2024-11-20 00:00:00 +0000 UTC 8 2} 
{2024-11-21 00:00:00 +0000 UTC 8 1} 
{2024-11-21 00:00:00 +0000 UTC 9 2} 
{2024-11-21 00:00:00 +0000 UTC 10 4} 
{2024-11-22 00:00:00 +0000 UTC 9 1}]
相关推荐
银河技术1 小时前
从脚本到 Operator:用 Go 构建可靠的微服务自动扩缩容控制器
开发语言·微服务·golang
草莓熊Lotso3 小时前
【C++ 基于微服务的即时通讯系统】etcd + brpc 从安装到服务注册发现全链路实战
网络·数据库·c++·redis·微服务·etcd
Lethehong9 小时前
Oracle 加个字段,目标库就报错?KFS 用“先拆后组“打通异构 DDL
数据库·oracle
Web极客码9 小时前
锁定真正的磁盘卡顿:我用 OpenCode 配合 eBPF 诊断 NVMe 队列深度延迟与 I/O 写放大
数据库·oracle
cspttty10 小时前
2027用户研究求职准备:应用统计学如何补齐研究设计与业务表达
大数据·数据库
roman_日积跬步-终至千里11 小时前
【数据Agent论文·查询与语义|05】Spider:为什么换一个数据库,模型就不会查了?
数据库·数据分析
猫咪很可爱11 小时前
Oracle RAC 启动失败排查:私网通信与内核参数优化实战
运维·数据库·oracle
XLYcmy12 小时前
《数字经济赋能城市低碳治理的路径研究检索报告》审阅与修改指导意见——基于完整检索报告体例的完整性诊断、学术规范核查与方法论纠偏 上
数据库·ai·chatgpt·文心一言·检索·知网·豆包
泡海椒12 小时前
JQuick-SQL 快速开始:注册内存表并执行查询
数据库·windows·sql
ss27312 小时前
PG实战笔记 | 09 PostgreSQL psql客户端基本操作
数据库·笔记·postgresql