编写SQL查询以查找至少出现三次的所有数字

时间:2015-07-23 03:20:40

标签: mysql select

我正在练习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

4 个答案:

答案 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