当前位置: 首页 > news >正文

两种方法解决SQL连续登录问题

目录

      • 一、需求及数据准备
      • 二、SQL处理逻辑
        • (1)连续序列构造法
        • (2)lag+累计求和构造法
      • 三、总结

一、需求及数据准备

需求:现有一张用户登录表user_login_records 记录用户一天内登录某个APP的时间,需要通过这张表找出至少连续登录N次的用户(或者每个用户最大连续登录次数)。连续定义:同一个用户相邻两条登录记录之前,没有其他用户登录记录(用户登录表内数据默认按登录时间依次升序排列)

CREATE TABLE `user_login_records` (`app_id` int NOT NULL COMMENT '应用ID',`user_id` int NOT NULL COMMENT '用户ID',`login_time` datetime NOT NULL COMMENT '登录时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户登录记录表'-- 批量插入用户登录数据
INSERT INTO user_login_records (app_id, user_id, login_time)
VALUES
(1, 1, '2025-10-20 08:20:00'),
(1, 2, '2025-10-20 08:45:00'),
(1, 2, '2025-10-20 08:46:00'),
(1, 2, '2025-10-20 09:22:00'),
(1, 3, '2025-10-20 10:15:00'),
(1, 3, '2025-10-20 10:16:00'),
(1, 2, '2025-10-20 10:20:00'),
(1, 2, '2025-10-20 11:00:00'),
(1, 2, '2025-10-20 11:20:00'),
(1, 2, '2025-10-20 11:22:00'),
(1, 6, '2025-10-20 14:00:00'),
(1, 6, '2025-10-20 14:05:00'),
(1, 6, '2025-10-20 14:25:00'),
(1, 6, '2025-10-20 14:30:00'),
(1, 1, '2025-10-20 16:30:00');

二、SQL处理逻辑

(1)连续序列构造法

思路:若用户连续登录,则记录序号必定连续。可构造2组连续的序列,相减即可获得一组常数列,即可用来区分不同的连续记录。一组连续可按所有人登录时间进行排序处理,一组可按每个用户登录时间进行分组排序。(注意:本题是求解同一天内用户连续登录多次的场景,如果是求解连续登录多天的情况,则需要对每天内登录多次的记录进行去重再处理

select user_id ,rk_sequence,count(*) as constant_length
from 
(select user_id,login_time,all_rk,user_rk ,all_rk-user_rk as rk_sequencefrom (select user_id ,login_time,row_number() over(order by login_time asc ) as all_rk ,row_number() over(partition by user_id order by login_time asc) as user_rk from user_login_records) t1
) t2
group by user_id ,rk_sequence

在这里插入图片描述
其中,rk_sequence可理解为序列连续序列起始的位置,cosntant_length为连续序列的长度;以用户2进行举例说明,用户2在一天内有2组连续登录的记录,一组连续登录了3次,一组连续登录了4次;在上述结果的基础上,求解连续登录N次和最大连续登录次数,只需要对结果进行聚合筛选即可


--(1)求解至少连续登录N次的用户
select distinct user_id 
from 
(select user_id,login_time,all_rk,user_rk ,all_rk-user_rk as rk_sequencefrom (select user_id ,login_time,row_number() over(order by login_time asc ) as all_rk ,row_number() over(partition by user_id order by login_time asc) as user_rk from user_login_records) t1
) t2
group by user_id ,rk_sequence
having count(*)>=N--(2)求解每个用户最大连续登录次数
select user_id ,max(constant_length) as max_cosntant_length
from 
(select user_id ,rk_sequence,count(*) as constant_lengthfrom (select user_id,login_time,all_rk,user_rk ,all_rk-user_rk as rk_sequencefrom (select user_id ,login_time,row_number() over(order by login_time asc ) as all_rk ,row_number() over(partition by user_id order by login_time asc) as user_rk from user_login_records) t1) t2group by user_id ,rk_sequence
) t3
group by user_id 
(2)lag+累计求和构造法

思路:
(1)首先需要对连续登录的用户进行标记,创建1个辅助列is_constant,通过lag函数比较当前记录和上一条记录的用户ID,如果相同,则表明该条为连续记录;如果不同,则表明为间断记录。
(2)其次,需要对这些连续记录进行分组标记,便于统计连续记录的条数。考虑当该条记录连续时,is_constant则为1,计算1-is_constant,则该数值为0;如果不连续,则1-is_constant对应数值为1;那么当我们对这列数1-is_constant进行累计求和时,则会得到这样的效果:当记录连续时,累计和不变;当记录一旦间断时,累计和将会发生变化,这样就可以实现对连续记录进行标记的效果
(3)对分组的连续记录计数,筛选即可

过程:
(1)对连续登录用户进行标记

  select user_id ,login_time ,case when user_id = lag(user_id,1) over(order by login_time asc) then 1 else 0 end as is_constantfrom user_login_records

在这里插入图片描述
(2)对连续记录进行分组标记

  select user_id ,login_time,is_constant,sum(1-is_constant) over(order by login_time asc ) as constant_flag from (select user_id ,login_time ,case when user_id = lag(user_id,1) over(order by login_time asc) then 1 else 0 end as is_constantfrom user_login_records) t 

在这里插入图片描述
(3)只要构建出连续分组标记,最终只要聚合计数统计即可

-- 1、统计至少连续登录N次的用户ID
select distinct user_id 
from 
(select user_id ,login_time,is_constant,sum(1-is_constant) over(order by login_time asc ) as constant_flag from (select user_id ,login_time ,case when user_id = lag(user_id,1) over(order by login_time asc) then 1 else 0 end as is_constantfrom user_login_records) t 
) tt 
group by user_id,constant_flag
having count(*)>=N-- 2、统计每个用户最大连续登录次数
select user_id,max(constant_length) as constant_length 
from 
(
select user_id ,constant_flag ,count(*) as constant_length
from 
(select user_id ,login_time,is_constant,sum(1-is_constant) over(order by login_time asc ) as constant_flag from (select user_id ,login_time ,case when user_id = lag(user_id,1) over(order by login_time asc) then 1 else 0 end as is_constantfrom user_login_records) t 
) tt 
group by user_id,constant_flag
) ttt 
group by user_id 

三、总结

方法一和二都是通过构建序列的方式来对连续记录进行分组标记;方法一主要是通过常数列=自增序列1-自增序列2方式进行构建,方法二则比较巧妙,需要通过连续记录标记的累计和,进行分组标记

http://www.dtcms.com/a/512012.html

相关文章:

  • 一种简易的python c++协同定位和dump数据的方式
  • 蒙帕视角丨图像高效端到端目标检测
  • 孟村网站建设虚拟资源站码支付wordpress
  • xv6 源码精读(二)开启MMU、一致性映射页表
  • 珠海网站建设尚古道策略长沙口碑好网站建设公司
  • =word插入公式后行距变大怎么办?-笔记
  • Android 接入 Google 和 Facebook 第三方登录指南(初始版)
  • Aspose.words关于builder.CellFormat.Width、row.Cells[0].CellFormat.Width的设置单元格宽度区别
  • 罗湖网站建设的公司哪家好阳泉做网站公司
  • 口碑好的共晶贴片机公司
  • 挑战概率直觉:蒙提霍尔问题的解密与应用
  • 网站域名哪些后缀更好给自己公司做个网站
  • 算法笔记 07
  • Steps + Input.TextArea + InfiniteScroll 联调优化
  • /dev/mem 原理及使用
  • 机关网站建设 方案泰安新闻完整版
  • Endpoint
  • 阿里巴巴双11微服务智能监控体系:从全链路追踪到AI自愈的技术实践
  • 在ros2 humble版本上安装D455相机并获取图像和深度信息
  • C++DirectX9坐标系与基本图元之渲染状态(RenderState)_0304
  • 网站建设app长春seo技术
  • 【C++】力扣hot100错误总结
  • C++中的vector讲解
  • 笔记【字符串,转义字符,注释】
  • visual studio安装本地帮助手册
  • 北京市基础建设质量监督局网站wordpress 插件怎么看
  • 大模型技术分析与演进逻辑
  • 苏州模板网站建站长沙网站建设推广
  • 从零起步学习MySQL || 第六章:MySQL数据库中的一条数据是如何存储的?(结合源码深度解析)
  • 微信小程序页面配置,基本语法,页面切换,tabbar全局配置