从 LeetCode 的题目再看 MySQL Explain

网友投稿 863 2023-05-24

从 LeetCode 的题目再看 MySQL Explain

从 LeetCode 的题目再看 MySQL Explain

题目

题目描述:编写一个 SQL 查询,查找所有至少连续出现三次的数字。并且给了一个示例,阿粉按照题目给的示例在本地创建了 Logs 表和插入相应的数据,如下:

我们可以看到在给定上面的 Logs 表中, 1 是唯一连续出现至少三次的数字,所以最后输出的结果是 1。

原始题目:LeetCode 180

刚看到题目的时候,阿粉一瞬间还是没反应过来,不知道该如何着手进行,思索了一下考虑是否可以用自连接来实现呢?然后根据题目的意思就写出了如下的 SQL。

SELECT DISTINCT  l1.num  FROM  `Logs` l1,  `Logs` l2,  `Logs` l3  WHERE  l1.num = l2.num   AND l2.num = l3.num   AND l1.id = l2.id - 1   AND l2.id = l3.id - 1

写完过后阿粉第一次提交,提示下面错误,可以看到是最后没有将返回重命名,调整了一下 SQL,就l1.num 改成l1.num as ConsecutiveNums 再次提交,得到的第二张通过的图。

看开始看到通过,阿粉还在想这道题也没什么啊,还是 so easy 的嘛。但是突然阿粉转念一想,这个题目说的是连续出现,并没有说 ID 是连续的啊,如果 ID 不连续的话,这种就不对了,还有就是如果需要连续 4 次出现的,5 次出现的数字呢?总不能一直自连接下去吧。如果写成这样那整个 SQL 就太不灵活了。

随后阿粉就看了一下官方解答以及相关评论,果不其然虽然官方给出的解答跟阿粉的一致,但是下面的评论却有很多小伙伴都在说这个 ID 不连续的问题。

既然反馈这种做法有问题,那自然就会有好事之者会想到解决办法,果然评论区的一个大佬给出了下面的这种解法

刚看到这个解法的时候,阿粉一下子没有看懂,把这个代码进行了提交,果然也是正常的通过了。而且这种解法不会被出现几次的条件给限制。抱着学习的心态,阿粉准备研究一下这条 SQL 里面的内容。

SQL 拆解

简单的了解了上面几个知识点过后,我们就可以对下面这条 SQL 进行拆解了。

select distinct Num as ConsecutiveNums from (   select Num,      case        when @currnet = Num then @count := @count + 1       when (@currnet := Num) is not null then @count := 1     end as CNT   from Logs, (select @currnet := null,@count := 0) as t ) as temp where temp.CNT >= 3

下面我们通过explain 命令看下整个 SQL 的执行过程,:

从select_type中我们可以看到总共派生了两个表,跟我们上面分析的一致;ID 为 3 的派生表的内容是select @current := null,@count := 0 定义两个变量并赋值,并且 id 越大越先执行;case 语句中第一个when 中判断当前扫描到的 num 值与定义的变量是否一致,如果一致则 count 加一,不一致则进行下一个when 条件判断,并将count 赋值为 1 返回;经过全表扫描过后,就得到了上面的中间表 temp 的内容;

不得不说,上面的方案是很完美的,不存在 ID 是否连续的问题,也不会多层自连接,而且也可以根据要求找出连续出现的次数,相对灵活。刚开始看到这个 SQL 的时候,阿粉并不清楚整个执行的过程,然后通过 explain 才渐渐明白整个执行过程, 而且对于在 SQL 中使用变量也有了一定的了解。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SQL Server 临时表的排序问题
下一篇:关系型数据库设计规范感悟
相关文章