【问题标题】:Write a SQL query to find all numbers that appear at least three times编写 SQL 查询以查找所有出现至少 3 次的数字
【发布时间】:2015-10-13 04:24:45
【问题描述】:

我正在练习 SQL 语言,遇到了一个类似的问题:

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

+----+-----+
| Id | Num |
+----+-----+
| 1  |  1  |
| 2  |  1  |
| 3  |  1  |
| 4  |  2  |
| 5  |  1  |
| 6  |  2  |
| 7  |  2  |
+----+-----+

例如,给定上面的 Logs 表,1 是唯一连续出现至少 3 次的数字。

我在网上找到了一个解决方案并进行了测试。但我真的不明白。大 解决方案的图片很清楚。 sq 表计算出现次数。但我不明白计算sq 的部分。我对MYSQL做了很多研究。 @counter := IF(@prev = Num, @counter + 1, 1) 表示如果 prev = Num,则使 counter = counter + 1,否则 counter = 1。(SELECT @counter:=1, @prev:=NULL) vars 表示创建一个表 vars,其中包括两列 counterpre

谁能帮我解释一下sq 部分的逻辑?或者SELECT中有这种表达方式的教程吗?我对 SQL 完全陌生,我知道这个问题可能很简单。谢谢你的帮助!

SELECT  DISTINCT(Num) AS ConsecutiveNums
FROM (
    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
) sq
WHERE how_many_cnt_in_a_row >= 3

【问题讨论】:

    标签: mysql select


    【解决方案1】:
    SELECT 
        distinct A.num as ConsecutiveNums 
    FROM
        LOGS A
    INNER JOIN Logs B
        on A.id=b.id+1
    INNER join Logs C
        on b.id=c.id+1
    WHERE a.num=b.num AND a.num=c.num
    ;
    

    【讨论】:

    【解决方案2】:

    这是另一个版本的答案...

    select distinct num 
      from ( 
              select num
                    ,lag(num,1) over() as lag1
                    ,lag(num,2) over() as lag2
                 from
                     logs
           ) as a
       where  num = lag1 = lag2
         and  lag1 = lag2
    

    【讨论】:

      【解决方案3】:

      尝试以下查询:

      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
      

      【讨论】:

      • 如果您添加解释,仅代码答案会更有帮助
      【解决方案4】:

      让我们浏览每条记录,看看这个查询是如何工作的。写的很好。

      选择...从

      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
      

      如果您的数据集一个接一个地有五个1s,则将检索第三个、第四个和第五个1。因此,DISTINCT(Num) 仅用于选择单个1。这只是聪明的想法。可以将WHERE 子句更改为WHERE ... = 3 insted of >= 3

      希望这是有道理的。

      【讨论】:

      • 非常感谢您的帮助!我很难选择哪一个作为正确答案,因为@djeison 也给出了正确的想法并且更早(但不如你的详细)。我总是不知道 stackoverflow 的正确答案的规则。第一个几乎正确的获得标记或绝对正确且更详细的一个。
      • 您选择了正确答案作为正确答案。 djeison 比我提前 14 分钟回答,这是一个有意义的正确答案。我添加了我的详细说明以供参考。所以保留 djeison 的帖子作为答案 - 这是我的建议。
      • 这简直太棒了。
      【解决方案5】:

      首先,下面这行只是初始化变量@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 | +-----+-----+

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 2011-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多