当前位置:   article > 正文

SQL窗口函数的使用_窗口函数 窗口子句 interval

窗口函数 窗口子句 interval

一.窗口函数的介绍

1.窗口函数实现的功能

1)具备分组和排序的功能
2)不改变原有数据库表行数
3)实现对分组后数据取值和聚合计算

2.与group by的区别

group by分组后会改变原表行数,一个类别只保留一行,窗口函数则会保留原有行

二.窗口函数的语法

1.窗口函数的构成

window_function_name(window_name/expression)
over
(
[partition_by]
[order_by]
[frame_definition]
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

窗口的数据集范围由[partition_by],[order_by],[frame_definition]共同确定

2.窗口函数的元素

在这里插入图片描述
1)窗口函数名window_function_name
静态窗口函数不能使用frame子句,滑动窗口函数使用order by 或frame子句函数区域变为当前限定的数据集
a.静态窗口函数

函数名参数描述
rank()间断的组内排序,1,1,3,4
dense_rank()不间断的组内排序,1,1,2,2,3,4
row_number()依次排序,1,2,3,4

执行后结果如下:
在这里插入图片描述
b.滑动窗口函数
取值函数

函数名参数描述
first_value()first_value(expr)分组后取第一行的值
last_value()last_value(expr)分组后取最后一行的值
lag()lag(expr,N,default)从当前行开始往前取第N行,默认为1,若没有返回default,默认值为null,返回值的类型必须和字段类型一样,字段为int,default才能设置成0
lead()lead(expr,N)从当前行开始往后取第N行,默认为1,若没有返回default,默认值为null
nth_value()nth_value(expr,N)返回分组内截至当前行的第N行
ntile()ntile(N)返回分桶号,返回范围从1到N

c.聚合函数

函数名参数描述
sum(expr)字段求和,有orderby是累加求和
max(expr)字段取最大值,有order by截止当前行最大值
min(expr)字段取最小值,有order by截止当前行最小值
count(expr)字段统计记录数
avg(expr)字段取平均值,有order by截止当前行平均值
percent_rank()累计百分比,(rank-1)/(rows-1)
cum_dist()累计分布值函数

2)分区函数partition_defintion
窗口按照指定字段进行分区,可以选择多个分区字段

3)排序函数order_definition
按照指定字段进行排序,表面是排序功能,实际为累计功能,当和聚合函数(sum、avg、min、max等)连用的时候,order by就是起累计作用。

4)框架函数frame_definition()
框架frame是当前分区的一个子集,frame_unit有两种,分别是ROWS和Range
在这里插入图片描述

基于行:
通常使用between frame_start and between frame_end,frame_start和frame_end支持如下关键字
CURRENT ROW 边界是当前行,一般与其他范围关键字配合
UNBOUNDED PRECEDING 分区中的第一行
UNBOUNDED FOLLOWING 分区中的最后一行
N PRECEDING 当前行减去expr的值
N FOLLOWING 当前行加上expr的值
eg:rows between PRECEDING AND 1 FOLLOWING 当前行、前一行、后一行共三行
eg:rows UNBOUNDED FOLLOWING 当前行到最后一行
eg:rows between UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 当前分区所有行,等同于不写
基于范围:
有些范围是无法用行来表示的,比如一周前的订单数,可以使用范围来表示窗口:INTERVAL 7DAY PRECEDING(hive和impla无法实现)
窗口固定的函数:rank()、dense_rank()、row_number()、lag(expr,N,default)、lead(expr,N,default)、Ntile()等
在这里插入图片描述
row与range的区别
rows:指定以行号来确定frame范围,是物理意义上的行
ranges:根据range去加减上下界,是逻辑意义上的行

SELECT  vin
        ,acquisition_time1
        ,data_avn_speed
        ,sum(cast(data_avn_speed as FLOAT)) over (PARTITION BY vin ORDER BY acquisition_time1 ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) as row1
        ,sum(cast(data_avn_speed as float)) over (PARTITION BY vin ORDER BY acquisition_time1 RANGE BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) as range1
      FROM
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
发现出现重复行,range会一次全部求和,row会一行一行计算求和

3.窗口函数的使用

1)窗口函数元素搭配
在这里插入图片描述

2)静态窗口函数使用方式
a.静态窗口函数由于是排序,必须使用order by,设定排序条件,否则会报错
在这里插入图片描述
b.partition by、order by和groupby一样,可以增加多个分组字段
c.静态窗口函数不能使用frame子句

SELECT      vin
            ,acquisition_time1
            ,rank1
            ,rank() over (PARTITION BY vin,rank1 ORDER BY acquisition_time1)
            ,dense_rank() over (PARTITION BY vin,rank1 ORDER BY acquisition_time1)
            ,row_number() over (PARTITION BY vin,rank1 ORDER BY acquisition_time1)
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3)滑动窗口函数-取值函数的使用方式
问题:截止到当前行如何受order by和框架函数影响?
first_value()(建议使用)
a.partiton by、order by、frame_definition可以省略

SELECT      vin
            ,acquisition_time1
            ,rank1
            ,data_avn_longitude
            ,first_value(data_avn_longitude) over()
            ,first_value(data_avn_longitude) over(ORDER BY acquisition_time1)
            ,first_value(data_avn_longitude) over(PARTITION BY vin ORDER BY acquisition_time1)
      FROM
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

first_value(data_avn_longitude) over(PARTITION BY vin ORDER BY acquisition_time1 ROWS BETWEEN 1 PRECEDING and 1 FOLLOWING)--加入框架函数,取前中后三行第一个值

    在这里插入图片描述

    last_value()
    a.partiton by、order by、frame_definition可以省略
    b.增加order by ,发现取的值不是分组中最后一个的值,Order的值变化了,基本上也就是当前行的值了,如果没有变化就取相同Order系列中的最后一项。
    c.建议使用first_value()+desc方式实现

    SELECT      vin
                ,acquisition_time1
                ,rank1
                ,data_avn_longitude
                ,last_value(data_avn_longitude) over()
                ,last_value(data_avn_longitude) over(PARTITION BY vin ORDER BY acquisition_time1)
          FROM
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述增加order by之后发现取的值不是分组中最后一个的值,因为默认是取到分组(可选)第一项到当前行的,如果要取整个组的最后一项可以增加RANGE参数来限定范围:

    SELECT LAST_VALUE(ID) OVER (PARTITION BY G ORDER BY seq RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) 
    FROM t
    • 1

    lag(expr,N,default) ,lead(expr,N,default),nth_value(expr,N)(hive不支持),ntile(N)

    SELECT      vin
                ,acquisition_time1
                ,rank1
                ,data_avn_speed
                ,first_value(data_avn_speed) over(PARTITION BY vin ORDER BY acquisition_time1) as first1
                ,lag(data_avn_speed,2) over(PARTITION BY vin ORDER BY acquisition_time1) as lag1
                ,lead(data_avn_speed,2) over(PARTITION BY vin ORDER BY acquisition_time1) as lead1
                ,ntile(4) over(PARTITION BY vin ORDER BY acquisition_time1) as nth
          FROM
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述
    ntile()会将数据集等分成N组,但是不支持frame_definition子句,必须包含order by子句
    在这里插入图片描述4)滑动窗口函数-取值函数的使用方式
    max()、sum()、min()
    结果取决于数据集范围,只有partition by,就是分区范围,增加order by 就是unbounded preceding and current row,增加框架函数就是框架函数的范围
    count()
    对数据集范围进行计数

    SELECT      vin
                ,acquisition_time1
                ,rank1
                ,data_avn_speed
                ,count(data_avn_speed) over (partition by vin order by acquisition_time1 rows between 2 preceding and 2 following)
                ,count(data_avn_speed) over(PARTITION BY vin)
                ,count(data_avn_speed) over (PARTITION BY vin ORDER BY acquisition_time1)
          FROM
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    a.使用frame_definition,对数据集范围计数
    b.只使用partition by 就是对分组计总数
    c.使用partition by和order by 就是unbounded preceding and current row范围计数,但是遇到重复行,会把重复行同时计算(逻辑上计数)
    在这里插入图片描述
    percent_rank()
    待定
    cume_dist()
    待定
    5)窗口数据集
    如果窗口数据集多次调用,可以简写

    -- 求每个人成绩的均值、个数、总分、最小值和最大值
    SELECT *,
        avg(成绩)   over w AS score_avg,
           count(成绩) over w AS score_count,
        sum(成绩)   over w AS score_sum,
           min(成绩)   over w AS score_min,
        max(成绩)   over w AS score_max
    FROM score
    WINDOW w AS (partition by 姓名 order by 学号)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    三.窗口函数的应用

    待更新

    参考链接
    MySQL 8.0窗口函数
    最全的SQL窗口函数介绍及使用
    SQL篇-常用窗口函数
    MySQL累计求和问题及窗口函数orderby的原理
    HIVE SQL 聚合函数与 rows between / range between详解
    SQL LAST_VALUE使用问题记录

    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/967101
    推荐阅读
    相关标签
      

    闽ICP备14008679号