每隔5分钟统计一次记录的应用实例

本文介绍如何使用SQL查询来统计电话报表中每5分钟内的电话数量,并提供了两种不同的精度(分和秒)下的SQL语句实例。

一张电话报表(id,time,telephone) time:表示顾客打入时记录的时间

实例如下:
1 2006-06-11 05:52:12 1360065460758
2 2006-06-11 06:09:05 1380138017292
3 2006-06-11 06:25:13 97363849310
4 2006-06-11 06:26:08 61763849310
5 2006-06-11 06:34:59 60054190811
6 2006-06-11 06:44:04 1397305138553
7 2006-06-11 06:51:30 60063849310
8 2006-06-11 06:53:14 92713061620671
9 2006-06-11 06:53:22 11713061620671
10 2006-06-11 06:58:34 32054196057
11 2006-06-11 07:04:42 92752581156

统计一下每隔5分钟打进电话多少个?
怎么写SQL语句啊
注意 我可能这样的数据有几万条

很明显,比如像鱼是按5分钟为步长生成了时间段,然后按时间段连接.保证了每个5分钟都被统计.

/*------------------------------------------------------------------
-- Author : htl258(Tony)
-- Date : 2010-04-17 22:01:29
-- Version: Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86)
Jul 9 2008 14:43:34
Copyright (c) 1988-2008 Microsoft Corporation
Developer Edition on Windows NT 5.1 <X86> (Build 2600: Service Pack 3)

------------------------------------------------------------------
*/
--> 生成测试数据表:tb

IF OBJECT_ID('[tb]') IS NOT NULL
DROP TABLE [tb]
GO
CREATE TABLE [tb]([id] INT,[time] DATETIME,[telephone] NVARCHAR(20))
INSERT [tb]
SELECT 1,N'2006-06-11 05:52:12',1360065460758 UNION ALL
--新增记录
SELECT 12,N'2006-06-11 05:53:12',136006546058 UNION ALL
SELECT 13,N'2006-06-11 05:54:12',136006546758 UNION ALL
SELECT 14,N'2006-06-11 05:55:12',136006540758 UNION ALL
SELECT 15,N'2006-06-11 05:54:12',136006560758 UNION ALL
-------
SELECT 16,N'2006-06-11 05:57:11',1360065460758 UNION ALL--精确到分归入后面的记录,精确到秒归到前面的记录
--
-----
SELECT 2,N'2006-06-11 06:09:05',1380138017292 UNION ALL
SELECT 3,N'2006-06-11 06:25:13',97363849310 UNION ALL
SELECT 4,N'2006-06-11 06:26:08',61763849310 UNION ALL
SELECT 5,N'2006-06-11 06:34:59',60054190811 UNION ALL
SELECT 6,N'2006-06-11 06:44:04',1397305138553 UNION ALL
SELECT 7,N'2006-06-11 06:51:30',60063849310 UNION ALL
SELECT 8,N'2006-06-11 06:53:14',92713061620671 UNION ALL
SELECT 9,N'2006-06-11 06:53:22',11713061620671 UNION ALL
SELECT 10,N'2006-06-11 06:58:34',32054196057 UNION ALL
SELECT 11,N'2006-06-11 07:04:42',92752581156
GO
--SELECT * FROM [tb]

-->SQL查询如下:
--
此查询精确到分:
SELECT ''+LTRIM(N+1)+'个5分钟' AS [5分钟系列],
COUNT(1) AS 记录数
FROM (
SELECT
N
=DATEDIFF(N,(SELECT MIN(TIME) FROM TB),TIME)/5
FROM TB
)
AS T
GROUP BY N
/*
5分钟系列 记录数
--------------------- -----------
第1个5分钟 5
第2个5分钟 1
第4个5分钟 1
第7个5分钟 2
第9个5分钟 1
第11个5分钟 1
第12个5分钟 1
第13个5分钟 2
第14个5分钟 1
第15个5分钟 1

(10 行受影响)
*/
--此查询精确到秒:
SELECT ''+LTRIM(N+1)+'个5分钟' AS [5分钟系列],
COUNT(1) AS 记录数
FROM (
SELECT
N
=DATEDIFF(SS,(SELECT MIN(TIME) FROM TB),TIME)/300
FROM TB
)
AS T
GROUP BY N

/*
5分钟系列 记录数
--------------------- -----------
第1个5分钟 6
第4个5分钟 1
第7个5分钟 2
第9个5分钟 1
第11个5分钟 1
第12个5分钟 1
第13个5分钟 2
第14个5分钟 1
第15个5分钟 1

(9 行受影响)
*/

-----------

附:一个按五分钟分段统计的例

create table tb(时间 datetime , 金额 int)
insert into tb values('2007-1-1 10:00:23' , 8 )
insert into tb values('2007-1-1 10:01:24' , 4 )
insert into tb values('2007-1-1 10:05:00' , 2 )
insert into tb values('2007-1-1 10:06:12' , 3 )
insert into tb values('2007-1-1 10:08:00' , 1 )
insert into tb values('2007-1-1 10:12:11' , 5 )
go

--时间段>=10:00:00 and 时间段<10:05:00
select dateadd(mi,(datediff(mi,convert(varchar(10),dateadd(ss,-1,时间),120),dateadd(ss,-1,时间))/5)*5,

convert(varchar(10),时间,120)) as 时间段,
count(*) as 行数,
sum(金额) as 总金额
from tb
group by dateadd(mi,(datediff(mi,convert(varchar(10),dateadd(ss,-1,时间),120),dateadd(ss,-1,时间))/5)*5,

convert(varchar(10),时间,120))
/*
时间段 行数 总金额
------------------------------------------------------ ----------- -----------
2007-01-01 10:00:00.000 3 14
2007-01-01 10:05:00.000 2 4
2007-01-01 10:10:00.000 1 5
(所影响的行数为 3 行)
*/

--时间段>10:00:00 and 时间段<=10:05:00
select dateadd(mi,(datediff(mi,convert(varchar(10),dateadd(ss,1,时间),120),dateadd(ss,1,时间))/5)*5,

convert(varchar(10),时间,120)) as 时间段,
count(*) as 行数,
sum(金额) as 总金额
from tb
group by dateadd(mi,(datediff(mi,convert(varchar(10),dateadd(ss,1,时间),120),dateadd(ss,1,时间))/5)*5,

convert(varchar(10),时间,120))
/*
时间段 行数 总金额
------------------------------------------------------ ----------- -----------
2007-01-01 10:00:00.000 2 12
2007-01-01 10:05:00.000 3 6
2007-01-01 10:10:00.000 1 5

(所影响的行数为 3 行)
*/



drop table tb



<think>我们之前已经实现了一个每小时重置Stats的扩展。现在用户的需求是:每隔一小时输出一次Stats数据并在输出后重置Stats重新统计。 实际上,我们的扩展已经实现了重置,但缺少在重置前的输出(比如日志或写入文件)。因此,我们需要修改扩展,在每次重置前将当前的统计数据输出(例如打印到日志或写入文件)。 修改思路: 1. 在reset_stats方法中,在保存当前统计数据和重置之前,先将当前统计数据输出(例如使用logger.info或自定义的输出函数)。 2. 可以配置输出方式(如日志、文件、外部系统等)。 下面我们修改之前的扩展,增加输出功能。同时,我们可以将输出配置为可定制的(比如通过设置指定输出方式)。 修改后的扩展代码: ```python # hourly_stats_reset.py from twisted.internet import task import logging import json import time from scrapy import signals from scrapy.exceptions import NotConfigured class HourlyStatsReset: """每小时输出并重置Scrapy Stats的扩展""" def __init__(self, stats, interval, output_file=None): self.stats = stats self.interval = interval # 重置间隔(秒) self.task = None self.history = [] # 保存历史统计数据 self.logger = logging.getLogger(__name__) self.output_file = output_file # 可选:输出到文件 @classmethod def from_crawler(cls, crawler): # 检查是否启用扩展 if not crawler.settings.getbool('HOURLY_STATS_RESET_ENABLED', False): raise NotConfigured interval = crawler.settings.getint('HOURLY_STATS_RESET_INTERVAL', 3600) output_file = crawler.settings.get('HOURLY_STATS_OUTPUT_FILE', None) # 创建扩展实例 ext = cls(crawler.stats, interval, output_file) # 连接信号 crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened) crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed) return ext def output_stats(self, stats_data): """输出统计信息""" # 输出到日志 self.logger.info(f"每小时统计信息: {json.dumps(stats_data, indent=2)}") # 输出到文件 if self.output_file: with open(self.output_file, 'a') as f: f.write(f"{time.ctime()} - 每小时统计信息:\n") f.write(json.dumps(stats_data, indent=2)) f.write("\n\n") def reset_stats(self): """输出当前统计信息,然后重置stats并保存历史记录""" # 获取当前统计信息 current_stats = self.stats.get_stats() # 输出统计信息 self.output_stats(current_stats) # 记录当前统计信息到历史 self.history.append({ 'timestamp': time.time(), 'stats': current_stats }) # 重置stats self.stats.clear_stats() # 记录重置事件 self.stats.set_value('hourly_reset_count', self.stats.get_value('hourly_reset_count', 0) + 1) self.stats.set_value('last_reset_time', time.time()) self.logger.info("Stats数据已重置") def spider_opened(self, spider): # 初始化重置计数器 self.stats.set_value('hourly_reset_count', 0) # 启动定时重置任务 self.task = task.LoopingCall(self.reset_stats) self.task.start(self.interval, now=False) # now=False表示第一次执行在interval秒后 def spider_closed(self, spider, reason): if self.task and self.task.running: self.task.stop() # 爬虫关闭时,输出一次当前的统计信息(最后一次未到整点的数据) # 注意:这里可以选择是否在关闭时重置,但通常我们只输出 current_stats = self.stats.get_stats() if current_stats: self.logger.info("爬虫关闭,输出最后一次统计信息") self.output_stats(current_stats) ``` ## 配置说明 在settings.py中: ```python # 启用扩展 EXTENSIONS = { 'yourproject.extensions.hourly_stats_reset.HourlyStatsReset': 500, } # 配置 HOURLY_STATS_RESET_ENABLED = True HOURLY_STATS_RESET_INTERVAL = 3600 # 重置间隔(秒) HOURLY_STATS_OUTPUT_FILE = 'hourly_stats.json' # 可选,将统计信息输出到文件(追加模式) ``` ## 使用说明 1. 扩展启动后,每小时会执行一次: - 输出当前统计信息(日志和可选的文件) - 重置stats - 记录重置次数 2. 爬虫关闭时,会输出最后一次统计信息(未到整点重置时间的数据) ## 自定义输出 如果需要将统计数据输出到其他位置(如数据库、消息队列等),可以重写`output_stats`方法。例如: ```python class CustomOutputHourlyStatsReset(HourlyStatsReset): def output_stats(self, stats_data): # 自定义输出逻辑 # 例如发送到数据库 self.logger.info("自定义输出...") # 这里可以添加数据库写入代码 ``` 然后在扩展中使用这个自定义类。 ## 注意事项 - 文件输出使用追加模式,确保每次输出不会覆盖之前的内容。 - 如果使用文件输出,注意文件权限和磁盘空间。 - 重置stats会清空所有计数器,包括Scrapy内置的(如item_scraped_count等)。请确保这种清零行为符合你的需求。 ## 高级选项 如果希望保留某些统计项不被重置(如总运行时间、总请求数等),可以在重置前将这些值记录下来,并在重置后重新设置。但Scrapy的stats设计是整体重置,如果需要部分重置,需要自行管理。 例如,在reset_stats方法中: ```python def reset_stats(self): current_stats = self.stats.get_stats() # 假设我们希望保留总运行时间(如果存在的话) uptime = current_stats.get('elapsed_time_seconds', None) # 输出 self.output_stats(current_stats) # 记录历史 self.history.append({ 'timestamp': time.time(), 'stats': current_stats }) # 重置stats self.stats.clear_stats() # 恢复总运行时间 if uptime is not None: self.stats.set_value('elapsed_time_seconds', uptime) # 记录重置事件 self.stats.set_value('hourly_reset_count', self.stats.get_value('hourly_reset_count', 0) + 1) self.stats.set_value('last_reset_time', time.time()) ``` 但注意:Scrapy内置的`elapsed_time_seconds`是从爬虫启动开始计算的,通常我们并不希望重置它。其他指标同理。 ## 总结 通过以上扩展,我们实现了: 1. 每小时输出统计信息 2. 重置stats重新计数 3. 保留历史记录(在内存中,也可自行扩展持久化) 4. 支持自定义输出 这样就能满足用户的需求了。 </think># Scrapy Stats每小时输出并重置的实现方案 要实现Scrapy的Stats数据每小时输出并重置,可以通过创建一个自定义扩展(Extension)来实现。下面是我的完整解决方案: ## 实现思路 1. 创建自定义扩展使用Twisted的定时器 2. 每小时输出当前统计信息 3. 重置Stats收集器 4. 保存历史统计数据用于分析 5. 确保爬虫关闭时输出最后一次统计 ## 完整实现代码 ```python # stats_hourly_output.py from twisted.internet import task import logging import json import time from scrapy import signals from scrapy.exceptions import NotConfigured class HourlyStatsOutputReset: """每小时输出并重置Scrapy Stats的扩展""" def __init__(self, stats, interval, output_file=None): self.stats = stats self.interval = interval # 重置间隔(秒) self.task = None self.history = [] # 保存历史统计数据 self.logger = logging.getLogger(__name__) self.output_file = output_file # 可选:输出到文件 @classmethod def from_crawler(cls, crawler): # 检查是否启用扩展 if not crawler.settings.getbool('HOURLY_STATS_RESET_ENABLED', True): raise NotConfigured interval = crawler.settings.getint('HOURLY_STATS_RESET_INTERVAL', 3600) output_file = crawler.settings.get('HOURLY_STATS_OUTPUT_FILE', None) # 创建扩展实例 ext = cls(crawler.stats, interval, output_file) # 连接信号 crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened) crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed) return ext def output_stats(self, stats_data): """输出统计信息""" # 输出到日志 self.logger.info(f"每小时统计信息: {json.dumps(stats_data, indent=2)}") # 输出到文件 if self.output_file: with open(self.output_file, 'a') as f: f.write(f"{time.ctime()} - 每小时统计信息:\n") f.write(json.dumps(stats_data, indent=2)) f.write("\n\n") def reset_stats(self): """输出当前统计信息,然后重置stats并保存历史记录""" # 获取当前统计信息 current_stats = self.stats.get_stats() # 输出统计信息 self.output_stats(current_stats) # 记录当前统计信息到历史 self.history.append({ 'timestamp': time.time(), 'stats': current_stats }) # 重置stats self.stats.clear_stats() # 记录重置事件 self.stats.set_value('hourly_reset_count', self.stats.get_value('hourly_reset_count', 0) + 1) self.stats.set_value('last_reset_time', time.time()) self.logger.info("Stats数据已重置") def spider_opened(self, spider): # 初始化重置计数器 self.stats.set_value('hourly_reset_count', 0) # 启动定时重置任务 self.task = task.LoopingCall(self.reset_stats) self.task.start(self.interval, now=False) # now=False表示第一次执行在interval秒后 def spider_closed(self, spider, reason): if self.task and self.task.running: self.task.stop() # 爬虫关闭时,输出一次当前的统计信息(最后一次未到整点的数据) current_stats = self.stats.get_stats() if current_stats: self.logger.info("爬虫关闭,输出最后一次统计信息") self.output_stats(current_stats) ``` ## 配置方法 在Scrapy项目的settings.py中添加以下配置: ```python # settings.py # 启用每小时输出并重置扩展 EXTENSIONS = { 'yourproject.extensions.stats_hourly_output.HourlyStatsOutputReset': 500, } # 配置选项 HOURLY_STATS_RESET_ENABLED = True HOURLY_STATS_RESET_INTERVAL = 3600 # 重置间隔(秒),默认3600秒(1小时) HOURLY_STATS_OUTPUT_FILE = 'hourly_stats.json' # 可选,将统计信息输出到文件 ``` ## 使用说明 1. **启动爬虫**:正常启动爬虫,扩展会自动运行 ```bash scrapy crawl myspider ``` 2. **查看输出**:每小时会在日志中看到类似输出: ``` INFO: 每小时统计信息: { "downloader/request_bytes": 456781, "downloader/request_count": 1234, "item_scraped_count": 3456, ... } ``` 3. **文件输出**:如果配置了`HOURLY_STATS_OUTPUT_FILE`,统计信息会追加到指定文件 4. **重置验证**:可通过以下方式检查重置次数: ```python # 在爬虫中访问 reset_count = self.crawler.stats.get_value('hourly_reset_count') ``` ## 高级选项 ### 1. 保留特定统计项 如果你希望保留某些统计项不被重置(如总运行时间),可以修改`reset_stats`方法: ```python def reset_stats(self): # 获取需要保留的统计值 uptime = self.stats.get_value('elapsed_time_seconds') current_stats = self.stats.get_stats() self.output_stats(current_stats) self.history.append({ 'timestamp': time.time(), 'stats': current_stats }) self.stats.clear_stats() # 恢复保留的统计值 self.stats.set_value('elapsed_time_seconds', uptime) # 更新重置计数器 reset_count = self.stats.get_value('hourly_reset_count', 0) + 1 self.stats.set_value('hourly_reset_count', reset_count) self.stats.set_value('last_reset_time', time.time()) ``` ### 2. 自定义输出格式 在`output_stats`方法中,可以自定义统计信息的输出格式: ```python def output_stats(self, stats_data): # 创建自定义格式的摘要 summary = f"统计时段: {stats_data.get('start_time', 'N/A')} - {time.ctime()}\n" summary += f"请求计数: {stats_data.get('downloader/request_count', 0)}\n" summary += f"抓取项目: {stats_data.get('item_scraped_count', 0)}\n" summary += f"错误数: {stats_data.get('log_count/ERROR', 0)}\n" self.logger.info(f"每小时统计摘要:\n{summary}") # 同时输出完整JSON到文件 if self.output_file: with open(self.output_file, 'a') as f: f.write(summary) f.write("完整统计:\n") f.write(json.dumps(stats_data, indent=2)) f.write("\n\n") ``` ## 注意事项 1. **时间精度**:Twisted的定时器精度受事件循环影响,可能有几秒钟误差 2. **分布式爬虫**:在分布式环境中使用时,需考虑统计数据的聚合问题 3. **内存使用**:历史记录存储在内存中,长时间运行爬虫需注意内存消耗 4. **重置影响**:重置会影响Scrapy默认的性能统计逻辑,请评估是否适合你的场景 这个实现方案能够精确控制统计数据的输出频率,同时保持统计数据的连续性,非常适合需要按时间段分析爬虫性能的场景[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值