当前位置: 首页 > Web前端 > JavaScript

SQL窗口函数

时间:2023-03-27 18:03:12 JavaScript

窗口函数形如:表达式OVER(PARTITIONBY分组字段ORDERBY排序字段)有两个能力:当表达式为rank()dense_rank()row_number()时,它有分组和排序能力.当表达式是聚合函数如sum()时,它具有累积聚合的能力。无论能力如何,窗口函数都不会影响数据行数,而是将计算分摊到每一行上。这两种能力需要分开来理解。上面的底表是示例底表,一共有8条数据,city1和city2是两个城市,每条数据下面都有region1到4,每条数据都有该地区的人口数据。分组排序如果按人口排序的话,ORDERBYpeople就可以了,但是如果我们要在同城内排序呢?这时候就要用到窗口函数的分组排序能力了:SELECT*,rank()over(PARTITIONBYcityORDERBYpeople)FROMtest这条SQL的意思是按城市组中的人排序。其实PARTITIONBY也是可选的。如果我们忽略它:SELECT*,rank()over(ORDERBYpeople)FROMtest也是有效的,但是这个语句相当于普通的ORDERBY,所以在使用窗口函数进行分组排序时,一般使用PARTITIONBY。各组排序函数的区别我们打印出rank()dense_rank()row_number()的结果:SELECT*,rank()over(PARTITIONBYcityORDERBYpeople),dense_rank()over(PARTITIONBYcityORDERBYpeople),row_number()over(PARTITIONBYcityORDERBYpeople)FROMtest其实从结果可以猜到,这三个函数在处理排序时遇到相同的值时,在排名统计逻辑上有如下区别:():value相同时相同rank,但占用rank号。dense_rank():当值相同时,排名相同,但不占用排名号,整体排名更紧凑。row_number():不管值是否相同,强制按照行号显示排名。上面的例子是可以优化的,因为所有的窗口逻辑都是一样的,我们可以用WINDOWAS把它提取成一个变量:SELECT*,rank()overwd,dense_rank()overwd,row_number()overwdFROMtestWINDOWwdas(PARTITIONBYcityORDERBYpeople)累积聚合前面我们说过,在万物中使用聚合函数会使查询变成一种聚合方式。如果不使用GROUPBY,聚合后返回的行数将被压缩为一行。即使使用GROUPBY,一般返回的行数也会大大减少,因为分组是聚合的。但是,使用窗口函数的聚合并没有导致返回行数的减少,那么这个聚合是如何计算的呢?我们不妨只看下面的例子:SELECT*,sum(people)over(PARTITIONBYcityORDERBYpeople)FROMtest可以看到在每个城市组中,都是按人排序并累加(相同的值会合并在一起),这是BI工具普遍提到的RUNNGIN_SUM的实现思路。当然,一般情况下,我们的排序规则使用的是永远不会重复的日期,所以不会遇到第一个红框合并计算的问题。累加函数还有avg()min()等。这些也可以应用于窗口函数。逻辑可以如下图理解:你可能会有疑惑。直接求和(上一行,下一行的结果)不是更方便吗?为了验证猜想,我们试试avg()的结果:可见,如果直接使用上一行结果的缓存,avg的结果肯定是不准确的,所以重新计算window的累计聚合对于每一行。当然不排除对sum、max、min进行额外性能优化的可能,但avg只能对每一行重新计算。与GROUPBY的结合Window函数可以与GROUPBY结合使用。遵循的规则是窗口范围对后续查询结果生效,所以是否进行GROUPBY并不重要。我们看下面的例子:按区域分组后的累积聚合是在GROUPBY之后的数据行粒度上进行的,而不是之前的明细行。小结窗函数在组内排序或累加GVM等计算场景中非常有用。我们只需要牢记两个知识点:组排序只有和PARTITIONBY结合才有意义。累积聚合用于查询结果行粒度,支持所有聚合函数。讨论地址为:Jingdu《SQL 窗口函数》·Issue#405·ascoders/weekly想参与讨论的请戳这里,每周都有新话题,周末或周一发布。前端精读——帮你过滤靠谱的内容。关注前端精读微信公众号版权声明:免费转载-非商业-非衍生保留属性(CreativeCommons3.0License)