SQL 窗口函数(Window Function)终极指南

文章目录

    • [1. 基础概念](#1. 基础概念)
    • [2. 常见窗口函数类型](#2. 常见窗口函数类型)
      • [2.1 聚合类](#2.1 聚合类)
      • [2.2 排名类](#2.2 排名类)
      • [2.3 窗口滑动计算类](#2.3 窗口滑动计算类)
      • [2.4 移动窗口类](#2.4 移动窗口类)
    • [3. 实战案例](#3. 实战案例)
      • [3.1 求每个部门薪资排名](#3.1 求每个部门薪资排名)
      • [3.2 环比、同比](#3.2 环比、同比)
      • [3.3 求累计和](#3.3 求累计和)
      • [3.4 每个学生成绩占班级的百分比](#3.4 每个学生成绩占班级的百分比)
    • [4. KPI 考核业务场景 --- 窗口函数 SQL 模板合集](#4. KPI 考核业务场景 — 窗口函数 SQL 模板合集)
      • [4.1 计算员工月度累计销售额(KPI 基础统计)](#4.1 计算员工月度累计销售额(KPI 基础统计))
      • [4.2 销售排名(同部门 Top 排名)](#4.2 销售排名(同部门 Top 排名))
      • [4.3 环比增长率(本月 vs 上月)](#4.3 环比增长率(本月 vs 上月))
      • [4.4 完成率统计(KPI vs 实际)](#4.4 完成率统计(KPI vs 实际))
      • [4.5 团队贡献占比(员工 vs 部门总额)](#4.5 团队贡献占比(员工 vs 部门总额))
      • [4.6 绩效分档(分位点计算)](#4.6 绩效分档(分位点计算))
      • [4.7 平均值对比(部门平均 vs 个人业绩)](#4.7 平均值对比(部门平均 vs 个人业绩))
      • [4.8 连续达标天数(运营 KPI)](#4.8 连续达标天数(运营 KPI))
      • [4.9 当月 Top-N 员工(带子查询过滤)](#4.9 当月 Top-N 员工(带子查询过滤))
    • [5. 优缺点](#5. 优缺点)

本文总结整理了一份 SQL 窗口函数(Window Function)终极指南,适用于复杂统计、简化 SQL 的应用场景,结合应用场景分析了其优缺点。

1. 基础概念

窗口函数是在 SELECT 查询结果集的每一行上执行聚合/排名/计算 的函数。

与普通聚合函数(SUM、AVG、COUNT 等)不同,窗口函数 不会收缩结果集,而是为每一行增加一个计算结果。

语法:

sql 复制代码
function_name(expression) OVER (
    PARTITION BY col1, col2
    ORDER BY col3
    ROWS BETWEEN ... 
)
  • PARTITION BY:对数据分组(类似 GROUP BY,但不会折叠行)

  • ORDER BY:定义计算顺序

  • ROWS BETWEEN:定义窗口范围(如前 N 行、到当前行为止)

2. 常见窗口函数类型

2.1 聚合类

在分组基础上给每行都输出一个结果:

sql 复制代码
SUM(sales) OVER(PARTITION BY region) AS region_sales,
AVG(sales) OVER(PARTITION BY region) AS region_avg
  • 每一行都能看到所属分区的总销售额/平均值。

2.2 排名类

sql 复制代码
ROW_NUMBER() OVER(PARTITION BY region ORDER BY sales DESC) AS rn,
RANK() OVER(PARTITION BY region ORDER BY sales DESC) AS rnk,
DENSE_RANK() OVER(PARTITION BY region ORDER BY sales DESC) AS drnk
  • ROW_NUMBER:严格递增,不考虑并列

  • RANK:有并列时跳号

  • DENSE_RANK:有并列但不跳号

2.3 窗口滑动计算类

sql 复制代码
LAG(sales, 1) OVER(ORDER BY month) AS prev_sales,
LEAD(sales, 1) OVER(ORDER BY month) AS next_sales,
sales - LAG(sales, 1) OVER(ORDER BY month) AS sales_diff
  • 常用于环比、同比计算。

2.4 移动窗口类

sql 复制代码
AVG(sales) OVER(ORDER BY month ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg
  • 最近三个月销售额的滑动平均。

3. 实战案例

3.1 求每个部门薪资排名

sql 复制代码
SELECT emp_id, dept_id, salary,
       RANK() OVER(PARTITION BY dept_id ORDER BY salary DESC) AS dept_rank
FROM employees;

3.2 环比、同比

sql 复制代码
SELECT month, sales,
       sales - LAG(sales, 1) OVER(ORDER BY month) AS mom_growth,
       sales - LAG(sales, 12) OVER(ORDER BY month) AS yoy_growth
FROM sales_data;

3.3 求累计和

sql 复制代码
SELECT month, sales,
       SUM(sales) OVER(ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM sales_data;

3.4 每个学生成绩占班级的百分比

sql 复制代码
SELECT student_id, score,
       score * 100.0 / SUM(score) OVER(PARTITION BY class_id) AS pct
FROM scores;

4. KPI 考核业务场景 --- 窗口函数 SQL 模板合集

4.1 计算员工月度累计销售额(KPI 基础统计)

sql 复制代码
SELECT
    emp_id,
    emp_name,
    month,
    SUM(sales_amount) OVER (PARTITION BY emp_id ORDER BY month) AS cum_sales
FROM sales;

📌 场景:考核每个员工的月度累计销售额,用于判断增长趋势。

4.2 销售排名(同部门 Top 排名)

sql 复制代码
SELECT
    emp_id,
    emp_name,
    dept_id,
    month,
    sales_amount,
    RANK() OVER (PARTITION BY dept_id, month ORDER BY sales_amount DESC) AS sales_rank
FROM sales;

📌 场景:考核月度销售冠军,支持并列名次(RANK vs DENSE_RANK vs ROW_NUMBER)。

4.3 环比增长率(本月 vs 上月)

sql 复制代码
SELECT
    emp_id,
    month,
    sales_amount,
    LAG(sales_amount, 1, 0) OVER (PARTITION BY emp_id ORDER BY month) AS prev_sales,
    ROUND(
        (sales_amount - LAG(sales_amount, 1, 0) OVER (PARTITION BY emp_id ORDER BY month))
        / NULLIF(LAG(sales_amount, 1, 0) OVER (PARTITION BY emp_id ORDER BY month), 0) * 100, 2
    ) AS growth_rate
FROM sales;

📌 场景:考核员工销售额环比增长(同比同理,替换 LAG(...,12))。

4.4 完成率统计(KPI vs 实际)

sql 复制代码
SELECT
    emp_id,
    month,
    target_amount,
    SUM(sales_amount) OVER (PARTITION BY emp_id, month) AS total_sales,
    ROUND(SUM(sales_amount) OVER (PARTITION BY emp_id, month) / target_amount * 100, 2) AS completion_rate
FROM sales_targets;

📌 场景:考核员工 KPI 目标完成情况。

4.5 团队贡献占比(员工 vs 部门总额)

sql 复制代码
SELECT
    emp_id,
    emp_name,
    dept_id,
    month,
    sales_amount,
    ROUND(sales_amount * 100.0 / SUM(sales_amount) OVER (PARTITION BY dept_id, month), 2) AS contribution_pct
FROM sales;

📌 场景:考核某员工对部门整体业绩的贡献度。

4.6 绩效分档(分位点计算)

sql 复制代码
SELECT
    emp_id,
    emp_name,
    month,
    sales_amount,
    NTILE(4) OVER (PARTITION BY month ORDER BY sales_amount DESC) AS quartile
FROM sales;

📌 场景:把员工销售分为四档(Q1 高绩效 → Q4 低绩效),用于绩效考核。

4.7 平均值对比(部门平均 vs 个人业绩)

sql 复制代码
SELECT
    emp_id,
    emp_name,
    dept_id,
    month,
    sales_amount,
    AVG(sales_amount) OVER (PARTITION BY dept_id, month) AS dept_avg,
    sales_amount - AVG(sales_amount) OVER (PARTITION BY dept_id, month) AS diff_from_avg
FROM sales;

📌 场景:员工业绩与部门均值对比,衡量超额/不足。

4.8 连续达标天数(运营 KPI)

sql 复制代码
SELECT
    emp_id,
    work_date,
    kpi_value,
    SUM(CASE WHEN kpi_value >= target THEN 1 ELSE 0 END)
        OVER (PARTITION BY emp_id ORDER BY work_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS consecutive_days
FROM daily_kpi;

📌 场景:考核运营人员 KPI 连续达标天数。

4.9 当月 Top-N 员工(带子查询过滤)

sql 复制代码
SELECT *
FROM (
    SELECT
        emp_id,
        emp_name,
        month,
        sales_amount,
        ROW_NUMBER() OVER (PARTITION BY month ORDER BY sales_amount DESC) AS rn
    FROM sales
) t
WHERE rn <= 3;

📌 场景:考核月度前三名员工。

5. 优缺点

优缺点 内容
优点 简化 SQL:不用子查询/自连接即可实现复杂统计。增强分析能力:轻松实现排名、累计、环比、同比。结果集完整:不会折叠行,统计与明细可共存。性能好:数据库优化器对窗口函数优化较好,尤其在 OLAP 场景。
缺点 学习曲线:语法复杂,理解成本高。性能风险:对大表、复杂 ORDER BY 的窗口函数,可能产生大规模排序和内存消耗。移植性差:不同数据库的窗口函数支持范围不同(如 MySQL 8 才支持,Oracle/PG/SQL Server 更完善)。调试难度:结果往往依赖分区、排序,稍有疏忽结果就偏差。

"人的一生会经历很多痛苦,但回头想想,都是传奇"。


相关推荐
天上掉下来个程小白44 分钟前
微服务-25.网关登录校验-网关传递用户到微服务
java·数据库·微服务
ta是个码农2 小时前
Mysql——日志
java·数据库·mysql·日志
没有bug.的程序员5 小时前
MyBatis 初识:框架定位与核心原理——SQL 自由掌控的艺术
java·数据库·sql·mybatis
Databend5 小时前
Databend 亮相 DTCC 2025:存算分离架构引领湖仓一体化
数据库
回家路上绕了弯5 小时前
ClickHouse 深度解析:从核心特性到实战应用,解锁 OLAP 领域新势能
数据库·后端
张铁铁是个小胖子6 小时前
mysql是怎样运行的(梳理)
数据库·mysql
许泽宇的技术分享7 小时前
当自然语言遇上数据库:Text2Sql.Net的MCP革命如何重新定义开发者与数据的交互方式
数据库·.net·text2sql·mcp
2301_803554528 小时前
redis学习
数据库·redis·学习
Java水解8 小时前
SQL 多表查询:数据整合与分析的强大工具
sql