【力扣 】查找所有至少连续出现三次的数字/求连续登录3天的用户数(SQL完成)

0. 题目

编写一个 SQL 查询,查找所有至少连续出现三次的数字。

返回的结果表中的数据可以按 任意顺序 排列。

输入:
Logs 表:
±—±----+
| Id | Num |
±—±----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
±—±----+
输出:
Result 表:
±----------------+
| ConsecutiveNums |
±----------------+
| 1 |
±----------------+
解释:1 是唯一连续出现至少三次的数字。

1. 关键

我们发现Num有连续的数字,但是Id有可能不是连续的,我们就需要通过对结果集再次编号,让其变成连续的。

核心思想是要想明白这个结论: 如果一个num连续出现时,那么它出现的[真实序列]-它出现的次数一定是个定值。 因为:

  • 假设一个num出现后,它的 真实序列 为 i ,同时假设它是第 k 次出现的; 差值为i-k.
  • 当它连续出现一次时,它的 真实序列 一定为 i+1 ; 它的出现次数显然也会+1,为 k+1 ; 差值为 i+1-(k+1)=i-k.
  • 当它连续出现第 n 次时,它的 真实序列 一定为 i+n;它出现的次数为 k+n;差值为 i+n-(k+n)=i-k.
  • 如果它不连续出现,假设m个其他num出现之后,它又出现了,它的真实序列为i+n+m+1,差值为i-k+m”,所以当m不为0时,差值不为i-k。

真实序列如何获得,我们可以用序号开窗函数处理。真实序列最好是连续的、不重复的,使用row_number。

官解是直接三表联查

SELECT DISTINCT
l1.Num AS ConsecutiveNums
FROM
Logs l1,
Logs l2,
Logs l3
WHERE
l1.Id = l2.Id - 1
AND l2.Id = l3.Id - 1
AND l1.Num = l2.Num
AND l2.Num = l3.Num
;

官解如果id不连续,根据Id计算会出现bug

2. 窗口函数

连续的关键: 真实序列-分区后出现的次数=定值

SELECT DISTINCT Num FROM (
SELECT Num,COUNT(1) as SerialCount FROM
(SELECT Id,Num,
ROW_NUMBER() over(order by id) -
ROW_NUMBER() over(partition by Num order by Id) as SerialNumberSubGroup
FROM ContinueNumber) as Sub
GROUP BY Num,SerialNumberSubGroup HAVING COUNT(1) >= 3) as Result

https://leetcode.cn/problems/consecutive-numbers/solutions/21537/sql-server-jie-fa-by-neilsons/

这其中ROW_NUMBER() over(order by id) 是num真实自然序列,
ROW_NUMBER() over(partition by Num order by Id)这个num是第几次出现的;

3.求连续登录3天的用户数

SELECT user_id
FROM (
SELECT
user_id,
login_date,
row_number() OVER(PARTITION BY user_id ORDER BY login_date) AS rn,
date_sub(login_date, rn) AS flag_date
FROM t_user
) tmp
GROUP BY tmp.user_id, date_sub(login_date, rn) – 每个用户每次连续登录的分块
HAVING COUNT(1) >= 3

注:上述代码仅求出了连续登录3天以上的所有user_id,并非user_id数。
login_date 可以作为真实序列(也可以row_number()over(order by login_date)
row_number() OVER(PARTITION BY user_id ORDER BY login_date) 是日期第几次出现

https://www.nowcoder.com/discuss/353148341368332288?sourceSSR=search

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值