MySQL 查询选择 -> 插入和删除所选行

标签 mysql sql select insert subquery

当用户连接到应用程序时,我有一个系统每 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/

相关文章:

mysql - 如何使用数组作为输入而不是仅使用单个值来执行 MySQL 查询?

mysql - 如何检查 SQL 中 VARCHAR(50) 列的值

php - mysql中的子选择数组

MySQL 查询卡在 'Sending Data' 上,似乎永远不会完成

php - Percona 复制不同步

php - 使用数据库中同一表中的另一列(ID 号)更改上传文件的名称

javascript - Angular 选择中的选定选项

mysql - 将多个删除查询组合成更少?

sql - 基于状态变化的分组

MySQL 添加、DATE_FORMAT 和 CONCAT_WS