本文转载自微信公众号《SQL数据库开发》,作者,平凡的世界。转载本文请联系SQL数据库开发公众号。最近帮业务部整理业务报表。其中一个要求就是即使某个指标的top10%等待时间最长,其实就是把等待时间倒序排序后,取结果集的top10%。这个需求在SQLServer和Oracle上很容易实现,甚至在MySQL8.0上也是如此。正好我们的业务数据库是MySQL5.7。首先介绍一下不同数据库平台的实现方法。SQLServer实现方法SQLServer上有一个TOPPercent方法,可以直接得到结果的前(或后)N%。比如我们有如下City表,我们可以获取前10%的数据记录,这样写:SELECTTOP10PERCENT*FROMCityORDERBYIDDESC结果如下:Oracle实现方法Oracle有一个ROWNUM伪列,可以用来帮助我们计算前N个百分比。ROWNUM伪列的特点:ROWNUM是按照插入记录时的先后顺序排序的。ROWNUM实际上并不存在。它是过滤结果集的排序。如果没有结果集,就没有ROWNUM。ROWNUM不能使用基表名作为使用ROWNUM作为前缀查询时,请注意:1)如果使用大于号(>),则只能使用(>0),其他不允许。2)如果使用小于号(<),则与一般情况相同。3)如果使用等号(=),则只能使用等于1(=1)。我们可以先计算整个表的记录行数SELECTCOUNT(*)CNTFROMCity然后根据count聚合查询乘以总行数来确定查询。行数SELECT0.1*COUNT(*)CNTFROMCity最后提取伪列小于总数据百分比的数据SELECT*FROMCITYWHEREIDIN(SELECTIDFROM(SELECTIDFROMCITYORDERBYIDDESC)WHEREROWNUM<(SELECTCOUNT(*)*0.1FROMCITY))注意:Oracle不支持子查询ORDERBY需要在外面嵌套一层。MySQL8.0的实现方法MySQL8.0的实现方法主要是使用窗口函数ROW_NUMBER()OVER()。其实就是给排序后的集合增加一个自增长列,类似于Oracle的ROWNUMSELECT*FROM(SELECT*,ROW_NUMBER()OVER(ORDERBYIDDESC)rnFROMCityORDERBYIDDESC)aWHEREa.rn<=(SELECT0.1*COUNT(*)FROMCity)MySQL5.X的实现方法我们知道MySQL5.X没有窗口函数ROW_NUMBER()OVER(),那么如何实现呢?这里需要使用变量来实现。其实思路就是创建一个自增栏目,只是方式不同而已。SELECTA.*,@row_num:=@row_num+1ASROW_NUMFROMCityA,(SELECT@row_num:=0)BORDERBYIDDESC这样我们就可以得到一个列自增的结果集,然后按照上面类似的方法取前10个%足够。SELECT*FROM(SELECTA.*,@row_num:=@row_num+1ASROW_NUMFROMCityA,(SELECT@row_num:=0)BORDERBYIDDESC)CWHEREC.ROW_NUM<=(@row_num*0.1)其实MySQL5.X也挺简单的,但是当时我并不是很想用变量,而是想看看有没有其他的方法。最后发现还是得用变量。上图是在不同平台上查找前N%数据库的方法。可以验证和存储代码以备将来使用。总结一下,涉及到一些知识点,需要自己多学习:SQLServer的TOPPERCENTOracle的ROWNUM,子查询排序ROW_NUMBER()OVER()MySQL变量
