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

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS Agent(兼容OpenClaw),2核4GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 窗口函数是SQL进阶关键,助你轻松实现分组排名、累计占比、移动平均等复杂分析。一行代码替代多重子查询,性能更优、逻辑更清。掌握它,告别低效取数,甩开80%同行!

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

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

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

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

-- 传统写法(不推荐,仅作对比)
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;

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

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

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()

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

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)

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

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

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. 分组内百分比

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不愁。

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

相关文章
|
23天前
|
JSON API PHP
韩国股票实时数据 KOSPI(主板)和 KOSDAQ(创业板)的实时行情、K 线及指数数据
StockTV API全面支持韩国股市,覆盖KOSPI主板(exchangeId=60)与KOSDAQ创业板(110),提供实时行情、K线、指数等数据。需配置countryId=11及API密钥,支持HTTP/WS双协议,含PHP对接示例与关键注意事项。
|
1月前
|
SQL 关系型数据库 MySQL
主键、外键和约束:让数据库“有规矩”才能不出错!|转行学DB第5天
本文用通俗易懂的语言讲解了主键(数据的唯一标识)、外键(表间关联)以及唯一约束、非空约束等其他常见约束规则。通过具体SQL示例展示了各种约束的使用方法,并分享了新手容易踩的坑和实用建议。
|
23天前
|
消息中间件 存储 运维
【Kafka核心】Kafka 3.0+ KRaft模式(替代ZooKeeper)核心原理与优势
本文系统解析Kafka 3.0+ KRaft模式全知识体系,涵盖背景演进、核心架构、Raft原理、元数据管理、部署运维、最佳实践等九大维度,深度对比ZK模式,详解Controller/Broker角色分离、__cluster_metadata日志机制与毫秒级故障恢复优势,助你掌握Kafka下一代原生元数据管理核心技术。
|
23天前
|
人工智能 机器人 测试技术
从成功率到能力画像:上海AI Lab推出具身操作仿真评测基座EBench
上海AI Lab推出EBench,突破单一成功率评测范式,构建可复现、可拆解的具身操作能力诊断框架。涵盖26类任务、5维能力标签与4类泛化测试,共794条用例,助力精准刻画模型强项、短板及真实泛化性。
165 2
|
1月前
|
SQL 人工智能 安全
AI圈开始“养马”了?聊聊龙虾退位、爱马仕登基
AI智能体“龙虾”(OpenClaw)的衰落与“爱马仕”(Hermes Agent)的崛起:前者因API限策与高危漏洞(CVSS 9.9)式微;后者以持久记忆、技能自生成、跨平台互通等实用能力破圈,成技术圈新“拐杖”。但技术无银弹,懂你的工具才是真助力。
|
19天前
|
数据采集 自然语言处理 算法
可计算元认知文本分析:肿瘤生物物理学语义基线的构建与边界信号检测
本研究首次为肿瘤生物物理学提供可计算的语义基线,揭示该学科围绕力学信号与细胞行为的核心知识结构,并量化了力学/黏附/成像阈值作为学科边界信号。相比传统综述,本工作从“学科如何说话”的元认知视角实现了可复现、可扩展、跨层次对齐的计量基准,为肿瘤生物物理学在精准医学、组织工程及材料科学中的跨学科协作提供了方法学支撑。
|
23天前
|
人工智能 并行计算 调度
ZStack dGPU:让虚拟机里的 GPU 也能按需切分
ZStack dGPU 是面向虚拟机的纯软件GPU动态切分方案,无需NVIDIA vGPU授权或MIG硬件限制,支持主流NVIDIA GPU。实现显存与算力按需分配、即时回收,推理性能损耗仅约7%,23.5小时零故障运行。补齐IaaS层GPU细粒度调度能力,提升私有云GPU利用率。(239字)
|
23天前
|
人工智能 运维 算法
AI Agent落地卡壳:不是大脑不够强,是环境太陌生?
某头部互联网公司AI Agent任务成功率不足30%,暴露“眼高手低”通病:大模型有“大脑”,却缺“四肢”。JBoltAI首创AI-Ready执行环境(AREE),从Java资产感知、确定性协议、事件驱动编排等五维重构智能体执行能力,显著提升效率与可靠性,推动AI从“能想”走向“会做”。
83 1