我正在练习SQL语言并得到一个类似的问题:
编写SQL查询以查找连续出现至少三次的所有数字。
+----+-----+
| Id | Num |
+----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+----+-----+
例如,给定上面的Logs表,1是连续出现至少三次的唯一数字。
我在线获得了解决方案并对其进行了测试。但我真的不明白。大
解决方案的图片很清楚。 sq
表计算出现次数。但我不明白计算sq
的部分。我对MYSQL做了很多研究。 @counter := IF(@prev = Num, @counter + 1, 1)
表示如果prev = Num,则使counter = counter + 1,否则counter = 1. (SELECT @counter:=1, @prev:=NULL) vars
表示创建一个表vars
,其中包含两列counter
和{{1 }}
任何人都可以帮我解释pre
部分的逻辑吗?或者sq
中是否有任何关于此类表达式的教程?我是SQL的新手,我知道这个问题可能很简单。谢谢你的帮助!
SELECT
答案 0 :(得分:6)
让我们浏览每条记录,看看这个查询是如何工作的。写得很好。
选择... FROM 强>
SELECT...FROM Logs y, (...) vars
是什么意思?
如果您有这样的表:create table test(field1 int)
包含3行,如下所示:
field1
-------
1
2
3
执行select * from test, (select @counter:=1, @prev:=NULL) vars
将导致
field1 @counter:=1 @prev=NULL
------- ------------ -----------
1 1 NULL
2 1 NULL
3 1 NULL
@counter
和@prev
是会话变量。它们分别初始化为1和NULL。所有行都与这些变量结合在一起,为您提供上面看到的内容。
子查询的逐行分析
专注于这个子查询。
SELECT
Num,
@counter := IF(@prev = Num, @counter + 1, 1) AS how_many_cnt_in_a_row,
@prev := Num
FROM Logs y, (SELECT @counter:=1, @prev:=NULL) vars
查询选择第一行ID = 1,Num = 1,并选择Num作为第一列。
对于第二列,它做了一些数学运算。它会检查@prev = Num
。那么,@ prev是NULL,因为它是如何初始化的。因此,@prev = Num
会导致错误。 IF
通常写为IF(condition, what-to-do-if-condition-is-true, what-to-do-if-condition-is-false)
。
IF(@prev = Num, @counter + 1, 1)
----------- ------------ --
condition do this do this if condition
if true is false
由于@prev为NULL且不等于Num,因此返回1。
对于第3列,查询只是将@prev重置为Num。这就是全部。现在让我们看看SELECT如何逐行进行并发挥其神奇作用。
Num @prev was @counter was @counter calculation @prev reset to Num
--- --------- ------------ ----------------------- ------------------
1 NULL 1 is @prev = 1? No. So 1 1
1 1 1 is @prev = 1? Yes! So 2 1
1 1 2 is @prev = 1? Yes! So 3 1
2 1 3 is @prev = 2? No. So 1 2
1 2 1 is @prev = 1? No. So 1 1
2 1 1 is @prev = 2? No. So 1 2
2 2 1 is @prev = 2? Yes! So 2 2
以上第2和第3列仅供参考。
现在子查询完成了它的工作,SELECT DISTINCT...
来了并问:从上面的结果中,只给我@counter为3或更高的行。结果将是
Num @counter @prev
---- -------- -----
1 3 1
如果您的数据集一个接一个地有五个1
,则将检索第3个,第4个和第5个1
。因此,DISTINCT(Num)用于仅选择单个1
。这只是聪明的想法。可以将WHERE
子句更改为WHERE ... = 3
>= 3
的{{1}}内容。
希望这是有道理的。
答案 1 :(得分:3)
首先,下面的行只是初始化变量@counter
和@prev
。有关它的更多信息,请检查User Defined Variables。
(SELECT @counter:=1, @prev:=NULL)
因此,sq
不是一个实际的表,但它可以作为别名使用,因此您可以引用这些内存中的变量。@counter
变量计算连续顺序的数量,前一个数字@prev
与实际的Num
不同,@counter
重置为1,计数过程重新开始。
为了更清楚,以下是sq
:
+-----+-----------------------+
| Num | how_many_cnt_in_a_row |
+-----+-----------------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
+-----+-----+
答案 2 :(得分:0)
尝试以下查询:
select ConsecutiveNums from(
select
case
when lag(Num) over (order by Id) = Num and Num=lead(Num) over (order by
Id) then Num
end as ConsecutiveNums
from Logs
)
where ConsecutiveNums is not null
答案 3 :(得分:0)
选择 不同的 A.num 作为 ConsecutiveNums 从 日志A INNER JOIN 日志 B 在 A.id=b.id+1 INNER 连接日志 C 在 b.id=c.id+1 其中 a.num=b.num 和 a.num=c.num