前几天发了一个微头条: SQL:求连续N天的登陆人员 竟然有近15万的推荐量和近5000阅读量。几天了,友友还在踊跃的讨论,提出自己的观点和解决办法,甚至有条友私信问我 “验证了吗”。

感动啊,感动…
所以,我连夜查了许多资料,尝试找到通用的解决方法,来把大(问)坑(题)填了。
连续登陆,有个特点:去重之后,对日期(按人分组)排序后是个等差数列。判断是否连续的关键是:(每组)日期减排序数之后全部相等。
以SQL Server 2019(2005及后续版本均可:支持 row_number()窗口函数)为例,给出两种方案。注意:不讨论需求合理性、不改变数据库结构,限制在SQL层面解决问题。
用户登陆表UserLogin

通用方案一:使用 ROW_NUMBER() 窗口函数
- 去重
每用户一天最多保留一条记录,并把时间转换为日期方便后续操作

- 使用row_number() over(partition by 用户id order by 登录日期) 进行排名

- 判断是否连续
在第二步的基础上,登陆时间 – 排名后(使用date_sub()函数),得到的结果是同一天,则说明是连续的;否则是不连续的。这里的排名,是个等差数列。
例如:2024-08-01减去它对应的排序数1,就是2024-07-31;2024-08-02减去它对应的排序数字2,就是2024-08-01;2024-08-03减去它对应的排序数字3,就是2024-08-02;到目前为止该用户已经连续登录三天了。就是这个逻辑,我们可以使用 date_sub() 函数。

- 对上一步的结果,分组聚合后过滤,得到想要的数据
说明:如果需求是求出所有登陆中,任意连续的N天记录,则要删除之前步骤中的where子句;如果是最后n天的情况下,再加上过滤,减少原始数据量,提高性能。

通用方案二:使用 LEAD() 窗口函数
大思路一样,只是和下面的行比较。不始上面的思路清楚。有许多步,是一样的,就不再一一做了。
感兴趣的友友们,可以试试。记得来这里炫一炫噢!
水平、时间有限,不中之处,请条友们不吝赐教!


因为上次发完,不能修改了。生发一次,友友们见谅。
这不就是我之前提供的思路么,用窗口函数解决,而且我的算法还考虑到了某段日期内每个用户连续登录多少天