本文转载请联系Java极客技术公众号。今天阿芬主要是想通过LeetCode的一个题目,给大家展示一下MySQL中变量的使用,以及通过Explain的解析,来展示SQL的执行过程。虽然我平时工作中用到mysql比较多,但是变量的使用相对于mysql来说比较少,所以阿芬第一眼看到的时候有点懵,但是相信大家肯定不会和阿芬一样。毕竟能关注我们公众号的读者都是优秀的。标题标题描述:编写一个SQL查询来查找在一行中至少出现3次的所有数字。并举了个例子,阿芬按照题目中给出的例子,在本地创建了Logs表,并插入了相应的数据,如下:我们可以看到,在上面给出的Logs表中,1是唯一至少出现3个的数字连续多次,所以最后的输出是1。原题目:LeetCode180刚看到题目的时候,阿芬一时还没有反应过来。我不知道如何进行。我想能不能用自连接来实现?然后我按照题目SQL的意思写了如下。SELECTDISTINCTl1.numFROM`Logs`l1,`Logs`l2,`Logs`l3WHEREl1.num=l2.numANDl2.num=l3.numANDl1.id=l2.id-1ANDl2.id=l3.id-1写入后对于第一个提交,提示如下错误。可以看到return最后没有改名,调整了SQL,将l1.num改为l1.num为ConsecutiveNums。再次提交,得到了第二张通过的图片。开始看过了,阿芬还想这道题没关系,还是那么容易。不过阿芬突然想了想,这个题目说的是连续出现,并没有说ID是连续的。如果ID不是连续的,这是错误的,如果需要连续出现4次,5次出现的数字呢?它不能一直连接。如果这样写,整个SQL就太死板了。然后阿芬看了看官方的回答和相关评论。果不其然,虽然官方的回答和阿芬的一致,但是下面评论里很多小伙伴都在讨论ID不连续的问题。既然这个反馈方式有问题,自然会有好心人想办法解决。果然,评论区有个大佬给出了如下解决方案。我明白了,我提交了这段代码,正常通过了。并且这个解法不会被多次出现的条件所限制。抱着学习的心态,阿芬准备研究一下这条SQL的内容。SQL拆解首先,这个SQL有太多让阿芬看不懂的地方。第一个是@符号,然后是:=然后还有whenthen语法的case,我平日在CRUD中从来没有遇到过。写了,不知道也没关系,google一下就知道了。网上查了下,@prev是声明变量的意思,:=操作是mysql的赋值操作,casewhenthenwhen后面是判断条件,满足条件就返回then之后的结果。需要注意的是,case只会返回第一个匹配结果,其余的会被忽略。简单了解了以上知识点后,我们就可以拆解下面的SQL了。selectdistinctNumasConsecutiveNumsfrom(selectNum,casewhen@currnet=Numthen@count:=@count+1when(@currnet:=Num)isnotnullthen@count:=1endasCNTfromLogs,(select@currnet:=null,@count:=0)ast)astempwheretemp。CNT>=3最外面的selectdistinctNumasConsecutiveNumsfrom()astempwheretemp.CNT>=3;我们可以看到中间的括号里面生成了一个临时表,表的名字叫temp,临时表中分别有Num和CNT两个字段。其实Num是Logs表中的个数,CNT是连续出现的累计次数,最后wheretemp.CNT>=3是根据需要的连续出现次数查询。派生语句SELECTNum,CASEWHEN@currnet=NumTHEN@count:=@count+1WHEN(@currnet:=Num)ISNOTNULLTHEN@count:=1ENDASCNTFROMLOGS,(SELECT@currnet:=NULL,@count:=NULL)ASt包含两个部分,一个是theninSelect时的情况,另一个是from(select@currnet:=null,@count:=null)astwhereselect@currnet:=null,@count:=null也是派生表,这里通过声明两个变量@currnet、@count并赋值为null。中间派生表temp的内容如下,通过生成一个记录每个数字出现次数的临时表来查询数据。我们通过explain命令来看整个SQL执行过程:从select_type可以看出一共导出了两张表,这和我们上面的分析是一致的;ID为3的派生表内容为select@current:=null,@count:=0定义两个变量并赋值,id越大执行越快;case语句中第一个when判断当前扫描到的num值是否与定义的变量一致,一致则给count加1,否则下一个when条件判断,给count赋值1返回;扫描全表后,得到上述中间表temp的内容;不得不说上面的方案是完美的,没有ID是否连续不会有多层自连接,连续出现的次数也可以根据需求找,比较灵活.刚开始看到这个SQL的时候,阿芬并不知道整个执行过程,后来通过explain逐渐了解了整个执行过程,对SQL中变量的使用也有了一定的了解。
