【题目】
编写一个 SQL 查询,查找所有至少连续出现三次的数字。
Id | Num |
---|---|
1 | 1 |
2 | 1 |
3 | 1 |
4 | 2 |
5 | 1 |
6 | 2 |
7 | 2 |
例如,给定上面的Logs
表, 1 是唯一连续出现至少三次的数字。
ConsecutiveNums |
---|
1 |
【题解】
法一:内连接
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
;
以上是官方解答,但存在问题:
1.num连续出现,但并不意味着id是连续的;
2.连续出现n次时,n很大sql语句过多需要优化。
于是有了法二。
法二:窗口函数
连续出现的数字是相同的数字,但有可能id是不连续的,所以需要对结果集进行再次编号,让其变为连续的。
# 1.对id进行从1开始的重新排序
select
id,num,
row_number() over (order by id) as nid
from logs
# 2. 对num值进行分组排序
select
id,num,
row_number() over (partition by num order by id) as numid
from logs
# 3.对步骤1和2中的nid-numid相减,若结果相等则表示数字连续出现,可得最终sql语句
select
distinct a.num as ConsecutiveNums
from
(
select
id,num,
(row_number() over (order by id)
- row_number() over (partition by num order by id)) as dif
from logs
) as a
group by a.num,a.dif
having count(*)>=3
法三:分析函数lag()
-- SELECT DISTINCT Num as ConsecutiveNums
-- FROM(
-- SELECT Id,Num,
-- LAG(Num,1)OVER(ORDER BY Id) as last_1,
-- LAG(Num,2)OVER(ORDER BY Id) as last_2
-- FROM Logs
-- ) as consecutivenum
-- WHERE consecutivenum.Num = consecutivenum.last_1
-- AND consecutivenum.last_1 = consecutivenum.last_2
法四:用户变量
利用case when语句判断连续出现的数字
select distinct Num as ConsecutiveNums
from (
select Num,
case
when @prev = Num then @count := @count + 1
when (@prev := Num) is not null then @count := 1
end as CNT
from Logs, (select @prev := null,@count := null) as t
) as temp
where temp.CNT >= 3
网友评论