https://www.nowcoder.com/feed/main/detail/cf3c154d344a4d858ffca4230ad2f391
这是一道非常经典的问题,连续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) AS res
FROM (
SELECT *, row_number() OVER (PARTITION BY id ORDER BY login_date) AS cum
FROM (
SELECT DISTINCT login_date, id
FROM Logins
) t0
) t1
) t2
GROUP BY id, res
HAVING COUNT(*) >= 5
) t3
LEFT JOIN Accounts ON t3.id = Accounts.id;
稍微做下说明:
t1表得到的结果就是对每个用户进行按日期标号。