分组排名不用窗口函数?那你还在写几十行的子查询

窗口函数:SQL进阶的分水岭,学会它甩开80%的取数员

我是小耶,干运营半路出家的野生DBA------写功课只是为了我踩过的坑,你们别再踩了!

一、没有窗口函数的痛苦回忆

以前想算"每个分类下销售额前3的产品",没有窗口函数的时候,写法是这样的:

css 复制代码
-- 传统写法(不推荐,仅作对比)
SELECT a.product_id, a.category, a.sales, COUNT(*) AS rn
FROM products a
JOIN products b ON a.category = b.category AND a.sales <= b.sales
GROUP BY a.product_id, a.category, a.sales
HAVING COUNT(*) <= 3;

这种写法难以理解、性能差、容易错。窗口函数出现后,一切变得简单。

二、窗口函数一行搞定排名

sql 复制代码
SELECT product_id, category, sales,
       ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS rn
FROM products;

外层加个 WHERE rn <= 3,查询结束。

语法拆解​:

  • ROW_NUMBER():编号函数
  • OVER:定义窗口
  • PARTITION BY category:按分类分组,每组内独立编号
  • ORDER BY sales DESC:组内按销售额降序排列

三、三个排名函数对比

函数 说明 示例结果(销售额100,90,90,80)
ROW_NUMBER() 唯一编号,不处理并列 1,2,3,4
RANK() 并列跳号 1,2,2,4
DENSE_RANK() 并列不跳号 1,2,2,3

实战选择建议​:

  • 分页取数据(每页10条)→ ROW_NUMBER()
  • 比赛排名(允许并列但跳过名次)→ RANK()
  • 工资等级(并列不跳过)→ DENSE_RANK()

四、累计占比(帕累托分析)

sql 复制代码
SELECT product, sales,
       SUM(sales) OVER (ORDER BY sales DESC) / SUM(sales) OVER () AS cum_pct
FROM products;

解释​:

  • SUM(sales) OVER (ORDER BY sales DESC):按销售额降序累计求和
  • SUM(sales) OVER ():全局总和(无PARTITION BY)
  • 两者相除得到累计占比

典型用法​:找到贡献前80%销售额的产品(二八法则)。

五、更多窗口函数实战场景

1. 移动平均(MA3)

sql 复制代码
SELECT date, sales,
       AVG(sales) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS ma3
FROM daily_sales;

2. 同比/环比(LAG / LEAD)

sql 复制代码
SELECT date, sales,
       LAG(sales, 1) OVER (ORDER BY date) AS prev_day_sales,
       sales / LAG(sales, 1) OVER (ORDER BY date) - 1 AS growth_rate
FROM daily_sales;

3. 分组内百分比

sql 复制代码
SELECT category, product, sales,
       sales / SUM(sales) OVER (PARTITION BY category) AS pct_in_category
FROM products;

六、性能注意事项

  1. 窗口函数会生成临时表 ,如果数据量很大(千万级),注意观察 Created_tmp_disk_tables 状态。
  2. ORDER BY 会排序 ,如果窗口内数据不需要排序,可以省略 ORDER BY 提升性能。
  3. 部分窗口函数(如 ​ROW_NUMBER())可以替代 ​LIMIT ​分组取TopN,比传统子查询快很多。
  4. MySQL 8.0+ 才支持窗口函数,低版本需要升级或者用变通写法。

七、快速记忆口诀

分组排名用窗口, PARTITION 分组,ORDER 排序, 三个函数看需求, 累计移动都能算。

八、实战练习建议

找一份订单表,自己尝试:

  • 每个用户最近3笔订单
  • 每月销售额环比增长率
  • 每个商品在所属分类中的销售额百分位

推荐刷题网站​:LeetCode 窗口函数专题(难度 中等 ~ 困难)

小耶在手,SQL不愁。

你工作中用到窗口函数最多的场景是什么?评论区分享一下,给新手一些灵感。

相关推荐
ZhiqianXia1 小时前
《The Design of Design》阅读笔记
前端·笔记·microsoft
有马贵将1 小时前
【5】微前端知识点总结
前端·架构
mkae1 小时前
eBPF高性能版fail2ban
前端
_柴富自由1 小时前
前端项目国际化解决方案
前端
isixe1 小时前
Uniapp 监听回到前台并全局唯一弹窗
前端
牛奶2 小时前
AI双层代码治理:Monorepo × Harness Engineering
前端·aigc·ai编程
蜡台2 小时前
H5使用Chrome 权限问题
前端·javascript·chrome
掘金一周2 小时前
你们觉得房贷多少,没有压力 | 沸点周刊 4.30
前端·人工智能·后端
小小码农Come on2 小时前
QML访问子项内容
前端·javascript·html