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

窗口函数: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不愁。

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

相关推荐
Chrischaan3 小时前
做 AI 塔罗小程序时,我为什么不让大模型自己抽牌:一次上线复盘
前端
这个DBA有点耶3 小时前
为什么UPDATE比SELECT危险得多?锁范围等于扫描行数
数据库·架构·代码规范
骑着蜗牛撵大象3273 小时前
LangChain 工具调用从声明到闭环:给智能体接上真实的手脚
前端
数据掘金3 小时前
百度统计后台页面数据异常?从手动调用时机开始排查
前端
hunteritself3 小时前
10 层 4K 实时剪辑,国产工作站进入广电制作核心
大数据·前端·人工智能·深度学习·transformer
踩着两条虫3 小时前
我在浏览器里“盖”了一个村:Vue + Three.js 大屏开发踩坑记
前端·vue.js·three.js
mbshqqb3 小时前
TypeScript基础教程之同步生成器
前端·javascript·typescript
嘟嘟同学和妮妮同学4 小时前
【升级】一个中国历史可视化站:皇帝时间线梳理、古代思想流派、诗词鉴赏 (2)
前端·html
沈麽鬼4 小时前
纸上代码
代码规范
暗夜行者之光4 小时前
LangGraph + MCP 实战:构建"自然语言查数据"的 ChatBI Agent
前端·后端