题目描述
这是一道非常经典的问题,连续n天登录的用户。之前在面试的时候也有被问到过,但是当时答的不好,这里在leetcode里再次碰到,所以做个总结,leetcode中问的是连续5天,但是我们希望将其拓展到连续n天。
以下是题目中的原始表
第一张是用户表,id列为主键。
第二张表为登录信息,因为其中包含重复行,表示一个用户在同一天多次登录,所以这张表无主键。
思路
说实话,第一次遇到这个问题,我是懵逼的,唯一想到的方法就是创建多张子表,每张表的日期依次向前推一天,然后多表连接。但是这种方法显然低效。同时,并不能解决任意天数n的情况,比如连续100天,总不能去创建100张子表吧?
OK,那么还有什么优雅的解法呢?
这里需要用到一个 row_number()方法,对每个用户的登录日期(去重后)按日期先后进行标号,然后用日期去减去这个标号。如果是一系列连续的日期,标号也是一系列连续递增的数,那么相减(日期减去对应标号)之后的结果就应该是相同的。然后我们对结果去进行count(),如果对于某个用户相同值的count大于等于n,那么就意味这这个用户存在连续n天登录。
以下是具体代码。
select Accounts.name
from
(select distinct id,res from (select id,date_sub(login_date,interval cum day) res from (select *,row_number() over(partition by id order by login_date) as cum from (select distinct login_date,id from Logins) as t0) as t1) as t2 group by id,res having count(*)>=5) as t3
left join
Accounts
on t3.id=Accounts.id;
稍微做下说明:
t1表得到的结果就是对每个用户进行按日期标号。
t2表得到的结果就是根据t1表中的日期和标号,进行相减得到res。
t3表就是根据t2表得到的相减结果res和用户id去进行group by 并筛选出count大于5的内容。
最后利用用户id和Accounts表连接,得到对应用户的名字。