我正在做一道 Leetcode 题。 2个类似的答案已经制定出来。但我不知道为什么一个是错的,另一个是对的。以下是问题链接。目标是编写一个 SQL 查询来查找至少连续出现 3 次的所有数字。
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 := 移至case end。
似乎else部分导致了一些错误,据我所知无法解释。
最佳答案
代码的第二个版本由于一个相当模糊的原因而无法工作。这部分:
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
的表达式已经具有此类动态内容。
总而言之,不建议在查询中设置变量,并且 future 版本的 MySql 可能不再支持它,如 Reference Manual 中所述。 :
Previous releases of MySQL made it possible to assign a value to a user variable in statements other than
SET
. This functionality is supported in MySQL 8.0 for backward compatibility but is subject to removal in a future release of MySQL.
关于mysql - WHERE 中的 CASE 子句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53577322/