SQL面试题1:连续登陆问题

news2025/1/16 0:35:25

引言

场景介绍:

许多互联网平台为了提高用户的参与度和忠诚度,会推出各种连续登录奖励机制。例如,游戏平台会给连续登录的玩家发放游戏道具、金币等奖励;学习类 APP 会为连续登录学习的用户提供积分,积分可兑换课程或其他福利。通过这些激励措施,平台希望用户能够养成持续使用产品的习惯,从而提升产品的活跃度和留存率。同时,对于平台运营者来说,分析用户的连续登录数据可以了解用户的使用习惯和忠诚度,进而优化产品功能和运营策略。

题目描述:

假设我们有一个记录用户登录信息的表,表名为 login_table,其中包含两个字段:uid(用户 ID)和 dt(登录日期)。现在需要完成以下三个任务:

  1. 查询连续登录超过三天的用户:找出在一段时间内,连续登录天数大于三天的用户列表。这有助于平台识别出那些高度活跃且对产品有较高忠诚度的用户,以便进一步进行精细化运营和奖励。
  2. 查询每个用户连续登录的最大天数:对于每个用户,统计其在所有登录记录中连续登录的最长时间段,这能帮助我们了解不同用户的活跃程度差异,为个性化运营提供数据基础。
  3. 查询一个用户连续登录的最大天数(可隔一天):在计算用户连续登录天数时,允许中间间隔一天,只要整体登录天数最多,就是我们要找的结果。比如用户在 1、3、5、6 日登录,那么其连续登录的最大天数为 6 天。这种统计方式可以更灵活地评估用户的活跃程度,考虑到了用户可能因为某些特殊情况中断一天登录,但整体仍保持较高的使用频率。

数据准备与代码实现

数据准备

1	2025-01-01
1	2025-01-02
1	2025-01-03
2	2025-01-07
2	2025-01-08
3	2025-01-09
3	2025-01-10
3	2025-01-12
3	2025-01-13

1. 查询连续登录超过三天的用户

思路:

  1. 用户登录记录编号:利用row_number()函数按uid分区并依dt升序排序生成序号rn,实现对各用户登录时间进行排序编号
  2. 计算连续登录首日:利用date_add函数将dt减去rn,计算每行对应的连续登录起始日期first_day
  3. 选出连续登录超过三天大用户:利用group byuidfirst_day分组,结合having筛选出分组行数大于等于3的记录,实现找出连续登录超三天的用户uid
with data as (
    select 1 as uid,'2025-01-01' as dt union all
    select 1 as uid,'2025-01-02' as dt union all
    select 1 as uid,'2025-01-03' as dt union all
    select 2 as uid,'2025-01-07' as dt union all
    select 2 as uid,'2025-01-08' as dt union all
    select 3 as uid,'2025-01-09' as dt union all
    select 3 as uid,'2025-01-10' as dt union all
    select 3 as uid,'2025-01-12' as dt union all
    select 3 as uid,'2025-01-13' as dt
),
data2 as (
    select uid,dt,row_number() over (partition by uid order by dt) rn from data
),
data3 as (
    select uid,dt,rn,date_add(dt,-rn) as first_day from data2
)
select uid from data3 group by uid,first_day having count(1) >= 3;

2. 查询每个用户连续登录的最大天数

思路:

  1. 用户登录记录编号:利用窗口函数row_number(),按uid分区并依dt升序排序生成序号rn,实现对各用户登录时间进行排序编号。
  2. 计算连续登录首日:利用date_add函数将dt减去rn,计算每行对应的连续登录起始日期first_day
  3. 统计分组登录天数:利用group byuidfirst_day分组,通过count(*)统计同一组合的天数login_day,以此统计出每个用户每段连续登录的天数。
  4. 获取用户最大连续登录天数:再次使用group byuid进行分组,通过max(login_day)从每个用户的多段连续登录天数中选出最大值,最终得到每个用户连续登录的最大天数。
with data as (
    select 1 as uid,'2025-01-01' as dt union all
    select 1 as uid,'2025-01-02' as dt union all
    select 1 as uid,'2025-01-03' as dt union all
    select 2 as uid,'2025-01-07' as dt union all
    select 2 as uid,'2025-01-08' as dt union all
    select 3 as uid,'2025-01-09' as dt union all
    select 3 as uid,'2025-01-10' as dt union all
    select 3 as uid,'2025-01-12' as dt union all
    select 3 as uid,'2025-01-13' as dt
),
data2 as (
    select uid,dt,row_number() over (partition by uid order by dt) rn from data
),
data3 as (
    select uid,dt,rn,date_add(dt,-rn) as first_day from data2
),
data4 as (
    select uid,first_day,count(*) as login_day from data3 group by uid,first_day
    )
select uid,max(login_day) from data4 group by uid;

3. 查询一个用户连续登录的最大天数,可以隔一天。解释:1、3、5、6登录则最大登录天数为6天。

思路:

  1. 查找上次登录时间:利用lag函数按uid分区并依dt升序排序,实现获取每行记录的上一次登录时间prev_dt
  2. 打标判断连续登录:利用datediff函数计算dtprev_dt的时间差,根据差值情况打标flag,实现区分是否连续登录,如果差值小于2天或者null(表示第一天)标记为0,都则标记为1。
  3. 计算连续登录标识和:利用sum函数按uid分组并依dt升序对flag求和,生成sum_flag,实现标识连续登录段。
  4. 计算每组时间差值:利用datediff函数对uidsum_flag聚类分组后计算max(dt)min(dt)的差值,实现获取每个分组的时间跨度。
  5. 获取最大连续登录天数:利用分组和max函数选出每个用户的最大时间差值max(diff)+1,实现得到每个用户连续登录的最大天数max_login

核心点:将相差值小于等于2的分到同一组里,然后采用分段思想计算每个分组分段的天数即为连续登录的天数。

with data as (
    select 1 as uid,'2025-01-01' as dt union all
    select 1 as uid,'2025-01-02' as dt union all
    select 1 as uid,'2025-01-04' as dt union all
    select 2 as uid,'2025-01-07' as dt union all
    select 2 as uid,'2025-01-08' as dt union all
    select 2 as uid,'2025-01-11' as dt union all
    select 2 as uid,'2025-01-13' as dt union all
    select 2 as uid,'2025-01-15' as dt union all
    select 3 as uid,'2025-01-09' as dt union all
    select 3 as uid,'2025-01-10' as dt union all
    select 3 as uid,'2025-01-12' as dt union all
    select 3 as uid,'2025-01-15' as dt
),
data2 as (
    select uid,dt,lag(dt, 1) over (partition by uid order by dt) prev_dt from data
),
data3 as (
    select uid,dt,prev_dt,if(datediff(dt, prev_dt) <= 2 or datediff(dt, prev_dt) is null, 0 ,1) flag from data2
),
data4 as (
    select uid,dt,prev_dt,flag,sum(flag) over(partition by uid order by dt) as sum_flag from data3
),
data5 as (
    select uid,datediff(max(dt),min(dt)) diff from data4 group by uid,sum_flag
)
select uid,max(diff)+1 as max_login from data5 group by uid;

知识点总结

1.窗口函数:lag、row_number

https://blog.csdn.net/Ahuuua/article/details/127136611

基本语法:函数名(参数) OVER (PARTITION BY 子句 ORDER BY 子句 ROWS/RANGE子句)

  • 函数名:如sum、max、min、count、avg等聚合函数以及lead、lag行比较函数等;
  • over: 关键字,表示前面的函数是分析函数,不是普通的集合函数;
  • 分组子句:over关键字后面挂号内的内容
lag()比较窗口函数

lag/lead(arg1,arg2,arg3):其中arg1为列名;arg2为偏移值,不能为负,默认为1;arg3超出记录窗口时的默认值,当不指定默认值时,则为null。lag:向前取n行; lead:向后取n行
在这里插入图片描述

row_number()排序窗口函数

排序窗口函数的主要作用是为查询结果中的每一行数据生成一个唯一的行号。这个行号是基于特定的排序规则生成的,并且可以根据不同的分组条件进行独立编号。

rankrow_numberdense_rank
100111
100121
90332

2. 日期计算函数

日期的三种形式:

  • DATE:YYYY-MM-DD,CURRENT_DATE()
  • DATETIME:YYYY-MM-DD HH:MM:SS、CURRENT_TIMESTAMP()
  • TIMESTAMP:时间戳,1973-12-30 15:30:00为19731230153000,UNIX_TIMESTAMP()
    常见计算函数:
  • DATEDIFF(end,start):计算end-start,单位天数
  • TIMESTAMPDIFF(unit,start,end):计算end-start,单位unit
    • unit:second、minute、hour、day、week、month、quarter(季度)、year
  • DATE_ADD(date, num):计算date+num后的时间,num参数表示要增加的时间间隔数量,正数表示增加时间,负数表示减少时间。
select CURRENT_DATE(),CURRENT_TIMESTAMP(),UNIX_TIMESTAMP();

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2277255.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode_5. 最长回文子串

最长回文子串https://leetcode.cn/problems/longest-palindromic-substring?envTypeproblem-list-v2&envId2cktkvj 给你一个字符串 s&#xff0c;找到 s 中最长的 回文子串 示例 1&#xff1a; 输入&#xff1a;s "babad" 输出&#xff1a;"bab" …

3D目标检测数据集——Waymo数据集

Waymo数据集簡介 发布首页&#xff1a;https://waymo.com/open/ 论文&#xff1a;https://openaccess.thecvf.com/content_CVPR_2020/papers/Sun_Scalability_in_Perception_for_Autonomous_Driving_Waymo_Open_Dataset_CVPR_2020_paper.pdf github&#xff1a;https://github.…

如何在 Linux、MacOS 以及 Windows 中打开控制面板

控制面板不仅仅是一系列图标和菜单的集合&#xff1b;它是通往优化个人计算体验的大门。通过它&#xff0c;用户可以轻松调整从外观到性能的各种参数&#xff0c;确保他们的电脑能够完美地适应自己的需求。无论是想要提升系统安全性、管理硬件设备&#xff0c;还是简单地改变桌…

Mycat读写分离搭建及配置超详细!!!

目录 一、Mycat产生背景二、Mycat介绍三、Mycat安装四、Mycat搭建读写分离1、 搭建MySQL数据库主从复制2、 基于mysql主从复制搭建MyCat读写分离 五、Mycat启动常见错误处理1、Caused by: io.mycat.config.util.ConfigException: SelfCheck### schema TESTDB refered by user u…

空指针:HttpSession异常,SpringBoot集成WebSocket

异常可能性&#xff1a; 404 &#xff1a; 请检查拦截器是否将请求拦截WebSocket握手期间HttpSession为空 HttpSession为空 方法一 &#xff1a; 网上参考大量的文档&#xff0c;有说跟前端请求域名有关系的。 反正对我来说&#xff0c;没啥用无法连接。 需使用 localhost&a…

【大数据】机器学习------决策树

一、基本流程 决策树是一种基于树结构的分类和回归方法&#xff0c;它通过对特征空间进行划分&#xff0c;每个内部节点表示一个特征测试&#xff0c;每个分支代表一个测试输出&#xff0c;每个叶节点代表一个类别或回归值。 特征选择&#xff1a;根据某种准则&#xff08;如信…

服务器数据恢复—raid5故障导致上层ORACLE无法启动的数据恢复案例

服务器数据恢复环境&故障&#xff1a; 一台服务器上的8块硬盘组建了一组raid5磁盘阵列。上层安装windows server操作系统&#xff0c;部署了oracle数据库。 raid5阵列中有2块硬盘的硬盘指示灯显示异常报警。服务器操作系统无法启动&#xff0c;ORACLE数据库也无法启动。 服…

Day05-后端Web基础——TomcatServletHTTP协议SpringBootWeb入门

目录 Web基础知识课程内容1. Tomcat1.1 简介1.2 基本使用1.2.1 下载1.2.2 安装与卸载1.2.3 启动与关闭1.2.4 常见问题 2. Servlet2.1 快速入门2.1.1 什么是Servlet2.1.2 入门程序2.1.3 注意事项 2.2 执行流程 3. HTTP协议3.1 HTTP-概述3.1.1 介绍3.1.2 特点 3.2 HTTP-请求协议3…

【已解决】【记录】2AI大模型web UI使用tips 本地

docker desktop使用 互动 如果需要发送网页链接&#xff0c;就在链接上加上【#】号 如果要上传文件就点击这个➕号 中文回复 命令它只用中文回复&#xff0c;在右上角打开【对话高级设置】 输入提示词&#xff08;提示词使用英文会更好&#xff09; Must reply to the us…

Deep4SNet: deep learning for fake speech classification

Deep4SNet&#xff1a;用于虚假语音分类的深度学习 摘要&#xff1a; 虚假语音是指即使通过人工智能或信号处理技术产生的语音记录。生成虚假录音的方法有"深度语音"和"模仿"。在《深沉的声音》中&#xff0c;录音听起来有点合成&#xff0c;而在《模仿》中…

Docker save load 镜像 tag 为 <none>

一、场景分析 我从 docker hub 上拉了这么一个镜像。 docker pull tomcat:8.5-jre8-alpine 我用 docker save 命令想把它导出成 tar 文件以便拷贝到内网机器上使用。 docker save -o tomcat-8.5-jre8-alpine.tar.gz 镜像ID 当我把这个镜像传到别的机器&#xff0c;并用 dock…

备战蓝桥杯 队列和queue详解

目录 队列的概念 队列的静态实现 总代码 stl的queue 队列算法题 1.队列模板题 2.机器翻译 3.海港 双端队列 队列的概念 和栈一样&#xff0c;队列也是一种访问受限的线性表&#xff0c;它只能在表头位置删除&#xff0c;在表尾位置插入&#xff0c;队列是先进先出&…

工厂物流管理系统方案(二):危险品车辆专用导航系统架构设计深度剖析

本文专为IT架构师、物流技术专家、软件开发工程师及对危险品运输导航技术有深入探索需求的读者撰写&#xff0c;旨在全面解析危险品车辆专用导航系统的架构设计&#xff0c;展现其技术深度与复杂性&#xff0c;为行业同仁提供权威的技术参考与实践指导。如需获取危险品车辆专用…

用 Python 从零开始创建神经网络(十九):真实数据集

真实数据集 引言数据准备数据加载数据预处理数据洗牌批次&#xff08;Batches&#xff09;训练&#xff08;Training&#xff09;到目前为止的全部代码&#xff1a; 引言 在实践中&#xff0c;深度学习通常涉及庞大的数据集&#xff08;通常以TB甚至更多为单位&#xff09;&am…

No.1|Godot|俄罗斯方块复刻|棋盘和初始方块的设置

删掉基础图标新建assets、scenes、scripts文件夹 俄罗斯方块的每种方块都是由四个小方块组成的&#xff0c;很适合放在网格地图中 比如网格地图是宽10列&#xff0c;高20行 要实现网格的对齐和下落 Node2D节点 新建一个Node2D 添加2个TileMapLayer 一个命名为Board&…

蓝桥云客第 5 场 算法季度赛

题目&#xff1a; 2.开赛主题曲【算法赛】 - 蓝桥云课 问题描述 蓝桥杯组委会创作了一首气势磅礴的开赛主题曲&#xff0c;其歌词可用一个仅包含小写字母的字符串 S 表示。S 中的每个字符对应一个音高&#xff0c;音高由字母表顺序决定&#xff1a;a1,b2,...,z26。字母越靠后…

刀客doc:快手的商业化架构为什么又调了?

一、 1月10日&#xff0c;快手商业化及电商事业部进行新一轮的架构调整。作为2025年快手的第一次大调整&#xff0c;变动最大的是负责广告业务的商业化事业部。快手商业化将原来的8个业务中心&#xff0c;现在统合成了5个&#xff0c;行业归拢看上去更加明晰了。 根据自媒体《…

6.2 MySQL时间和日期函数

以前我们就用过now()函数来获得系统时间&#xff0c;用datediff()函数来计算日期相差的天数。我们在计算工龄的时候&#xff0c;让两个日期相减。那么其中的这个now函数返回的就是当前的系统日期和时间。 1. 获取系统时间函数 now()函数&#xff0c;返回的这个日期和时间的格…

mock服务-通过json定义接口自动实现mock服务

go-mock介绍 不管在前端还是后端开发过程中&#xff0c;当我们需要联调其他服务的接口&#xff0c;而这个服务还没法提供调用时&#xff0c;那我们就要用到mock服务&#xff0c;自己按接口文档定义一个临时接口返回指定数据&#xff0c;以供本地开发联调测试。 怎么快速启动一…

sparkSQL练习

1.前期准备 &#xff08;1&#xff09;建议先把这两篇文章都看一下吧&#xff0c;然后把这个项目也搞下来 &#xff08;2&#xff09;看看这个任务 &#xff08;3&#xff09;score.txt student_id,course_code,score 108,3-105,99 105,3-105,88 107,3-105,77 105,3-245,87 1…