当前位置: 首页 > 科技观察

如何在不同的数据库平台上获取topN%的记录?

时间:2023-03-20 13:59:08 科技观察

最近帮业务部整理业务报表。其中一个需求就是即使某个指标的前10%的等待时间最长,实际上是将等待时间倒序排序后,取结果集的前10%。这个需求在SQLServer和Oracle上很容易实现,甚至在MySQL8.0上也能实现,但恰好我们的业务数据库是MySQL5.7。先介绍一下不同数据库平台的实现方法。SQLServer实现方法SQLServer上有一个TOPPercent方法,可以直接取结果的前(或后)N个百分点。比如下面这张City表:我们可以这样写top10%的数据记录:SELECTTOP10PERCENT*FROMCityORDERBYIDDESC结果如下:Oracle实现方法Oracle有一个ROWNUM伪列,可以用来帮助我们计算前一百N美分。ROWNUM伪列的特点:ROWNUM按照记录插入的顺序排序。ROWNUM其实并不存在,它是对过滤后的结果集进行排序,如果没有结果集,就不会有ROWNUM。ROWNUM不能以基表名称为前缀。在使用ROWNUM查询时,请注意:1)如果使用大于号(>),则只能使用(>0),其他的不可以。2)如果使用小于号(<),则与一般情况相同。3)如果使用等号(=),则只能使用等于1(=1)。我们可以先计算整个表的记录行数。SELECTCOUNT(*)CNTFROMCity然后将聚合查询项的总数乘以百分比来确定要查询的项数。SELECT0.1*COUNT(*)CNTFROMCity最后取出伪列小于普通数据百分比的数据。SELECT*FROMCITYWHEREIDIN(SELECTIDFROM(SELECTIDFROMCITYORDERBYIDDESC)WHEREROWNUM<(SELECTCOUNT(*)*0.1FROMCITY))注意:Oracle不支持子查询中的ORDERBY,并且它需要在Nest一级之外重新排序。MySQL8.0的实现方法MySQL8.0的实现方法主要是使用窗口函数ROW_NUMBER()OVER()。其实就是在sortedcollection中加入一个自增列,有点类似于Oracle的ROWNUM。SELECT*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%的数据库的方法。可以验证和存储代码以备将来使用。综上所述,涉及到一些知识点,需要自己多学习:TOPPERCENTofSQLServer。Oracle的ROWNUM,子查询排序。ROW_NUMBER()OVER()。MySQL变量。