WHERE

时间:2018-12-02 04:10:24

标签: mysql sql case-when

我在做一个leetcode问题。得出了2个类似的答案。但是我不知道为什么一个是错误的而另一个是正确的。以下是问题链接。目标是编写一个SQL查询来查找至少连续出现三次的所有数字。

https://leetcode.com/problems/consecutive-numbers/

表看起来像

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

正确的版本:

select distinct Num as ConsecutiveNums
from Logs, (select @prev := -1, @count := 0) as Init
where (@count := case when @prev = (@prev := Num) then @count + 1 else 1 end) >= 3

输出:

| ConsecutiveNums |
|-----------------|
|       1         |

版本错误:

select distinct Num as ConsecutiveNums
from Logs, (select @prev := -1, @count := 0) as Init
where (case when @prev = (@prev := Num) then @count := @count + 1 else @count :=  1 end) >= 3

输出:

| ConsecutiveNums |
|-----------------|
|       1         |
|       2         |

唯一的区别是@count:=被移至案例结尾

似乎 else 部分引起了一些错误,据我所知无法解释。

4 个答案:

答案 0 :(得分:1)

第二个版本的代码由于相当晦涩的原因而无法正常工作。这部分:

else @count :=  1

...具有一个没有动态成分的表达式。 MySql以不再次执行该分配的方式来优化其执行计划,而是仅返回@count的当前值。这是因为MySql变量实际上并不是设计为在查询执行期间 进行修改的。当您仍然决定使用该副作用时,必须注意这种“优化”行为。

您可以尝试迫使MySql每次 进行分配。这可以通过在分配的表达式中包含变量或字段引用来完成。例如,您可以使用:= if(@count, 1, 1)而不是:= 1。结果是相同的(总是1),但是现在每次遇到它时,它都会被重新评估和分配:

where (case when @prev = (@prev := Num)  
            then @count := @count + 1
            else @count := if(@count, 1, 1)
       end) >= 3

您可以想到其他替代表达式,例如:= 1+Num*0,只要有对某些变量/字段的引用,它就能解决问题。

查看您提供的查询的第一个版本,您会发现分配给@count的表达式已经具有这种动态内容。

总而言之,不建议在查询中设置变量,如Reference Manual所述,MySql的未来版本可能不再支持该变量:

  

以前的MySQL版本使得可以在SET以外的语句中为用户变量分配值。 MySQL 8.0支持此功能以实现向后兼容,但是在将来的MySQL版本中可能会删除该功能。

答案 1 :(得分:0)

因为您没有将“> = 3”与count进行比较。我们正尝试对这三个连续数字进行测试。在错误的版本中,不确定为什么会有“ =-10”。 “错误”版本的更正版本是:

SELECT num AS ConsecutiveNums
FROM   logs,
       (SELECT @prev := -1,
               @count := 0) AS Init
WHERE ( @count := CASE
           WHEN @prev = ( @prev := num ) THEN @count := @count + 1
           ELSE @count
         end ) >= 3

我还添加了一个不同的测试用例,以确保:

{"headers": {"Logs": ["Id", "Num"]}, "rows": {"Logs": [[1, 2], [2, 1], [3, 1], [4, 6], [5, 2], [6, 2], [7, 2]]}}

不更改测试用例的默认值将给出“ 1”,该测试用例应返回“ 2”

答案 2 :(得分:0)

DECLARE @max_id INTEGER
SET @max_id = (SELECT COUNT(*) FROM seat)

SELECT CASE WHEN id < @max_id THEN case when id%2<>0 then id+1 when id%2=0 then id-1 end
            WHEN id = @max_id THEN case when id%2=0 then id-1 else id
       END id
      ,student
FROM seat
ORDER BY id

SET @max_id = (SELECT max(id) FROM Seat) 选择 案件 当 id!=@max_id THEN 案件 当 id%2!=0 那么 id+1 当 id%2=0 则 id-1 结尾 当 id= @max_id THEN 案例
当 id%2=0 则 id-1 当 id%2!=0 THEN id 结尾 结束编号 , 学生 从座位
按 id 排序`

答案 3 :(得分:-1)

如果连续意味着id递增“ 1”(如示例数据中所示),则不需要变量-甚至不需要变量:

select t1.num
from t t1 join
     t t2
     on t2.id = t1.id + 1 and t2.num = t1.num join
     t t3
     on t3.id  = t1.id + 2 and t3.num = t1.num;

如果您有三个以上的连续值或一个与多行匹配的num,那么您可能想要select distinct num