MySQL 窗口函数

金歌  金牌会员 | 2024-8-22 17:26:15 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 715|帖子 715|积分 2145

1,窗口函数

1.1,什么是窗口函数

MySQL窗口函数是一种强大的工具,用于在查询中实验复杂的统计分析,而不必要改变表的结构或数据。MySQL从8.0版本开始支持窗口函数,这些函数也被称为分析函数,由于它们能够处理惩罚相对复杂的报表统计分析场景。
窗口的意思是将数据进行分组,每个分组便是一个窗口,这和利用聚合函数时的group by分组类似,但与聚合函数不同的地方是: 聚合函数(比方:sum/avg/min/max)会针对每个分组(窗口)聚合出一个结果(每一组返回一个结果)。 窗口函数会对每一条数据进行盘算,并不会使返回的数据变少(每一行返回一个结果)
1.2,基本语法

  1. -- 匿名窗口
  2. SELECT
  3.         <窗口函数> over (partition by <分组列名> order by <排序列名>)
  4. FROM `表名`
  5. -- 显式窗口
  6. SELECT
  7.         <窗口函数> OVER w
  8. FROM `表名`
  9. WINDOW w AS (partition by <分组列名> order by <排序列名>)
复制代码
<窗口函数>的位置,可以放以下两种函数:

  • 聚合函数:如SUM、AVG、COUNT、MAX、MIN等,可以在不合并行的情况下盘算每行的聚合值。
  • 专用窗口函数:

    • 排序函数:包括RANK、DENSE_RANK、ROW_NUMBER等,用于为数据集中的每行分配一个唯一的排名或编号。
    • 偏移函数:包括LAG和LEAD等,用于获取当前行之前的或之后的指定偏移量的值
    • 值函数:FIRST_VALUE和LAST_VALUE返回窗口分区中第一行或最后一行的值,而NTH_VALUE则返回窗口内偏移指定offset后的值。

   由于窗口函数是对where或者group by子句处理惩罚后的结果进行操作,所以窗口函数一样平常出现在select子句或者order by子句中。
where, group by, having都不可引用该列,由于这些语句实验在select之前,此时函数尚未盘算出值。
  2,函数详解

原始数据如下,表名:class

2.1,聚合函数

窗口操作不会将多组查询行折叠成单个输出行。相反,它们为每一行产生一个结果:
  1. SELECT
  2.         *,
  3.         -- 总计
  4.         SUM(score) OVER () AS sum1,  
  5.         -- 按course分组求和
  6.           SUM(score) OVER (PARTITION BY course) AS sum2,
  7.           -- 按course分组累计求和
  8.         SUM(score) OVER (PARTITION BY course ORDER BY score DESC) AS sum3       
  9. FROM `class`
复制代码

  1. SELECT
  2.         *,
  3.         SUM(score) OVER w AS sum,
  4.         AVG(score) OVER w AS avg,
  5.         MIN(score) OVER w AS min,
  6.         MAX(score) OVER w AS max,
  7.           COUNT(score) OVER w AS count
  8. FROM `class`
  9. WINDOW w AS (PARTITION BY course ORDER BY score DESC)
复制代码

   留意分数雷同时,分组累计(标黄处)的处理惩罚逻辑(见:《3,进阶用法》)
  2.2,排序函数

  1. SELECT
  2.         *,
  3.         ROW_NUMBER() OVER w AS 'row_number',
  4.         RANK() OVER w AS 'rank',
  5.         DENSE_RANK() OVER w AS 'dense_rank'
  6. FROM `class`
  7. WINDOW w AS (PARTITION BY course ORDER BY score DESC)
复制代码

   三者的区别如下:
row_number() 排序雷同时不会重复,会根据顺序排序,即:1、2、3、4;
rank() 排序雷同时会重复,序号有空隙,即1、2、2、4这样的排序结果;
dense_rank() 排序雷同时会重复,序号无空隙,即1、2、2、3这样的排序结果;
  求每门课程的前两名:
  1. SELECT * FROM (
  2.         SELECT
  3.                 *,
  4.                 RANK() OVER (PARTITION BY course ORDER BY score DESC) AS `rank`
  5.         FROM `class` ) f
  6. WHERE `rank` <= 2
  7. // 窗口函数得到的列别名不能用于where, group by, having等子句,
  8. // 因为这些语句执行在select之前,此时函数尚未计算出值。
  9. // 以下写法是错误的:
  10. SELECT
  11.         *,
  12.         RANK() OVER (PARTITION BY course ORDER BY score DESC) AS `rank`
  13. FROM `class`
  14. WHERE `rank` <= 2
复制代码

如果每门课程只必要前两条数据,可把RANK() 函数换成 ROW_NUMBER()
2.3,偏移函数

语法:LEAD(字段, 偏移量, 填充值)
偏移量默认为1,填充值默认为NULL
  1. SELECT
  2.         *,
  3.         -- 获取前面一行的score
  4.         LAG(score) OVER W AS `lag`,
  5.         -- 获取后面第二行score,且无数据填充0
  6.         LEAD(score, 2, 0) OVER W AS `lead`
  7. FROM `class`
  8. WINDOW w AS (PARTITION BY course ORDER BY score DESC)
复制代码

2.4,值函数

  1. SELECT
  2.         *,
  3.         -- 获取第一行的score
  4.         FIRST_VALUE(score) OVER w AS `first`,
  5.         -- 截止到当前行,获取最后一行score
  6.         LAST_VALUE(score) OVER w AS `last`,
  7.         -- 截止到当前行,获取最后2行score
  8.         NTH_VALUE(score, 2) OVER w AS `second`,
  9.         -- 截止到当前行,获取最后3行score
  10.         NTH_VALUE(score, 3) OVER w AS `third`
  11. FROM `class`
  12. WINDOW w AS (PARTITION BY course ORDER BY score DESC)
复制代码

留意了:从结果看,我们对FIRST_VALUE()很清楚,就是获取的第一个值,但是LAST_VALUE()和NTH_VALUE获取的值跟我们想象中的不太一样呢? 没错,LAST_VALUE()和NTH_VALUE是获取的截止到当前为止的值,而不是整个组的最后一个值后指定的值(见:《3,进阶用法》)。
3,进阶用法

  1. <窗口函数> over (
  2.                                 partition by <用于分组的列名>
  3.                        order by <用于排序的列名>
  4.                        rows/range 窗口子句
  5.                        )
复制代码
rows/range:窗口子句,主要用来限定分组(也称窗口)的行数和数据范围。
窗口子句必须和order by 子句同时利用,如果指定了order by 子句未指定窗口子句,则默认为RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,即从当前分组出发点到当前行。
行比力分析函数lead和lag无窗口子句。
窗口子句常用语法:


  • CURRENT ROW:当前行
  • UNBOUNDED:无界限(出发点或终点)
  • PRECEDING:往前
  • FOLLOWING:以后
如上文《2.4,值函数》,如果想获取整个窗口的LAST_VALUE()和NTH_VALUE:
  1. SELECT
  2.         *,
  3.         -- 获取第一行的score
  4.         FIRST_VALUE(score) OVER w AS `first`,
  5.         -- 获取最后一行score
  6.         LAST_VALUE(score) OVER w AS `last`,
  7.         -- 获取最后2行score
  8.         NTH_VALUE(score, 2) OVER w AS `second`,
  9.         -- 获取最后3行score
  10.         NTH_VALUE(score, 3) OVER w AS `third`
  11. FROM `class`
  12. WINDOW w AS (
  13.                         PARTITION BY course
  14.                         ORDER BY score DESC
  15.                         ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
  16.                         )
复制代码

rows 和range区别:

  • rows是物理窗口,即根据order by 子句排序后,取的前N行及后N行的数据盘算(与当前行的值无关,只与排序后的行号干系)。
  • range是逻辑窗口,即根据order by 子句排序后,取的前N行及和当前行有雷同order by值的所有行数据盘算。
比方在《2.1,聚合函数》飘黄部分,由于默认窗口字句是RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,所以改成把"RANGE"改成"ROWS"就是逐条统计:
  1. SELECT
  2.         *,
  3.         -- 默认RANGE
  4.         SUM(score) OVER w AS sum1,
  5.         -- 指定ROWS
  6.         SUM(score) OVER (w ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS sum2,
  7.         -- 默认RANGE
  8.         COUNT(score) OVER w AS count1,
  9.         -- 指定ROWS
  10.         COUNT(score) OVER (w ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS count2
  11. FROM `class`
  12. WINDOW w AS (PARTITION BY course ORDER BY score DESC)
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表