当用户连接到应用程序时,我有一个系统每 2 到 5 秒对数据库执行一次 ping 操作。根据他的连接,ping 时间范围可能会更长,例如 10 秒左右。
例子:
Pings: 1,4,6,8,9,12,16,20,50,180,187,189,200,203,206,210 ...
我正在运行一个查询以获取 ping 之间不超过 1 分钟的范围,将它们分组,这样我就可以知道用户连接了多长时间:
这是我运行的用于选择结果的查询,正如@fancyPants 在这个问题上所建议的那样: MySQL query to group results by date range?
select
userid, groupnum,
min(ping) as start_date,
max(ping) as end_date,
max(ping) - min(ping) as duration
from (
select
*,
@groupnum := if(@prevUser != userId, @groupnum + 1, @groupnum),
@groupnum := if(ping - @prevTS > 60, @groupnum + 1, @groupnum) as groupnum,
@prevUser := userid,
@prevTS := ping
from
Table1 t
, (select @groupnum:=1, @prevTS:=NULL, @prevUser:=NULL) vars
order by userid, ping
) sq
group by userid, groupnum
产生以下结果:
user: X | start_date: 1 | end_date: 50 | duration: 49
user: X | start_date: 180 | end_date: 210 | duration: 30
我需要帮助,向这个查询添加一个将执行以下操作的语句。
第一。将选定的行插入到一个新表中,该表具有查询返回的完全相同的架构:
id: auto_increment| user: X | start_date: 1 | end_date: 50 | duration: 49
id: auto_increment| user: X | start_date: 180 | end_date: 210 | duration: 30
第二。删除在查询中选择并插入到新表中的选定行。
此查询将由服务器上的 cronjob 每 10 分钟运行一次。所以我可以清理 ping 表,它会受到严重打击,然后将我们要显示给我们的冲浪者的值存储到一个新的表中。
在新查询中,我需要一个子句来过滤未过期的 ping。未过期的 ping 是在 cron 运行的当前时间之前不超过 60 秒完成的 ping。例如,如果 now = 100,则最后一次抓取的 ping 不能小于 41。这样,当 cron 运行时,我不会从仍在 ping 数据库的用户中选择行。
可以在一次查询中完成吗,还是需要两次?
谢谢,
最佳答案
(跟进 my previous answer )
ping_timestamp 列中到底存储了什么? Unix 时间戳或其他?我假设它是 unix 时间戳。
创建将保存用户事件数据的表:
create table user_activity (
user_id int(11) not null
, start_date int(11) not null
, end_date int(11) not null
, duration int(11) not null
);
跳过尚未关闭的区间聚合数据:
set @rnum = 1;
set @cut_off = unix_timestamp() - 60;
insert
into user_activity
select user_id
, min(ping_timestamp) start_date
, max(ping_timestamp) end_date
, max(ping_timestamp)-min(ping_timestamp) duration
from ( select user_id
, ping_timestamp
, @rnum := if(ping_timestamp - @prev_ping_ts > 60, @rnum+1, @rnum) rnum
, @prev_ping_ts := ping_timestamp
from ping_data
order by user_id, ping_timestamp
) t
group by user_id, rnum
having end_date <= @cut_off
;
之后我们可以根据user_activity表中的数据删除处理过的行:
delete t
from ping_data t
join ( select user_id
, max(end_date) max_timestamp
from user_activity
group by user_id
) ua
on t.user_id = ua.user_id
where t.ping_timestamp <= ua.max_timestamp
;
关于MySQL 查询选择 -> 插入和删除所选行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19061452/