窗口函数,SQL进阶分水岭:一行代码解决排名、环比,数据分析效率翻倍!
今日关键词窗口函数、排序分析、累计计算、OVER子句、MySQL 8.0前面我们已经掌握了数据库的“骨架”表结构、“加速器”索引以及“逻辑大师”游标与存储过程。但当我们面对复杂的排名、累计、同比环比分析时传统的聚合函数GROUP BY往往显得力不从心——它会把行“压扁”让我们无法同时看到明细数据和聚合结果。所以今天我们解锁SQL进阶路上的分水岭技术——窗口函数Window Function它就像是给数据库装上了一副“透视眼镜”让我们在不丢失任何一行明细数据的前提下进行跨行的统计分析用一行代码解决排名、累计、环比问题数据分析效率翻倍接下来小学妹就把窗口函数分享给大家让你少走弯路少踩坑。一、什么是窗口函数——数据的“逻辑透视镜”窗口函数Window Function也叫OLAP函数Online Analytical Processing它允许我们在结果集的“子集”即窗口上进行聚合或计算而不需要将行折叠成单个输出行。 类比你有一张全班成绩表。聚合函数就像“全班平均分”只给你一个数字窗口函数则能在每一行旁边加一列“全班平均分”让你知道每个人的分数和平均分的差距同时保留每个人的详细信息。窗口函数 vs 聚合函数函数类型结果行数典型用途聚合函数 GROUP BY减少行数每组一行每个班级的平均分窗口函数保持原行数每行旁边显示班级平均分二、窗口函数的基本语法SELECT列名,窗口函数()OVER(PARTITIONBY分组列ORDERBY排序列)AS别名FROM表名;**窗口函数**如ROW_NUMBER()、RANK()、SUM()、AVG()等OVER()定义窗口的大小和顺序PARTITION BY分组可选不加则整个表为一个窗口ORDER BY窗口内的排序重要 可以把窗口理解为GROUP BY的分组但每一行都留在结果中。三、三大类窗口函数新手必学排名函数最常用函数说明例子分数90,90,80ROW_NUMBER()连续编号不分先后1,2,3RANK()跳跃排名相同分数并列1,1,3DENSE_RANK()连续排名相同分数并列1,1,2实战查询每个部门的员工按工资排名SELECTname,department,salary,ROW_NUMBER()OVER(PARTITIONBYdepartmentORDERBYsalaryDESC)ASrow_rank,RANK()OVER(PARTITIONBYdepartmentORDERBYsalaryDESC)ASrank_rank,DENSE_RANK()OVER(PARTITIONBYdepartmentORDERBYsalaryDESC)ASdense_rankFROMemployees;聚合函数 窗口累计、移动平均支持在窗口中使用SUM、AVG、COUNT、MAX、MIN。实战计算每个月的累计销售额SELECTmonth,sales,SUM(sales)OVER(ORDERBYmonth)AScumulative_salesFROMsales_data;实战计算过去3个月的移动平均销售额SELECTmonth,sales,AVG(sales)OVER(ORDERBYmonthROWSBETWEEN2PRECEDINGANDCURRENTROW)ASmoving_avgFROMsales_data;ROWS BETWEEN 2 PRECEDING AND CURRENT ROW表示“从当前行往前的2行到当前行”共3行。取值函数高级函数说明LAG(列名, offset)取当前行前面第offset行的值LEAD(列名, offset)取当前行后面第offset行的值FIRST_VALUE() / LAST_VALUE()窗口内第一行/最后一行的值实战计算每个月的销售额环比增长率SELECTmonth,sales,LAG(sales,1)OVER(ORDERBYmonth)ASprev_month_sales,(sales-LAG(sales,1)OVER(ORDERBYmonth))/LAG(sales,1)OVER(ORDERBYmonth)*100ASgrowth_rateFROMsales_data;四、实战案例学生成绩排名 班级对比假设有stu_score表(id, name, class, score)。需求显示每个学生的姓名、班级、分数显示全校排名RANK()显示班级内排名显示班级最高分MAX()窗口SELECTname,class,score,RANK()OVER(ORDERBYscoreDESC)ASschool_rank,RANK()OVER(PARTITIONBYclassORDERBYscoreDESC)ASclass_rank,MAX(score)OVER(PARTITIONBYclass)ASclass_max_scoreFROMstu_score;结果示例nameclassscoreschool_rankclass_rankclass_max_score小明1班981198小红1班952298小刚2班973197五、窗口函数避坑指南❌版本限制MySQL 5.7 及更早版本不支持窗口函数必须使用 MySQL 8.0。如果你还在用旧版本建议升级或者使用复杂的自连接Self-Join来模拟但性能极差。❌性能陷阱如果不写PARTITION BY且数据量巨大窗口函数会扫描全表进行计算非常消耗内存。建议 尽量配合索引使用ORDER BY的列最好有索引。❌NULL值处理排序函数如RANK遇到NULL值时通常会将其视为最小值或者导致排序结果不符合预期。建议 在计算前使用WHERE 列名 IS NOT NULL过滤或用COALESCE处理。六、今日学习心得核心思想 窗口函数 保留明细 跨行计算。执行顺序 记住它在SELECT阶段执行所以不能直接在WHERE中过滤通常需要嵌套一层查询或使用 CTE。版本注意 确保你的环境是 MySQL 8.0 或 PostgreSQL 或 SQL Server老版本 MySQL 玩不转这个。 我是数据库小学妹一个用设计师思维学数据库的转行人。我们一起把复杂的技术变得简单有趣本文为个人学习总结所有示例基于 MySQL 8.0。如果你的版本低于8.0部分窗口函数不可用建议升级或使用其他方式替代。