文章目录
- 
- [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 更完善)。调试难度:结果往往依赖分区、排序,稍有疏忽结果就偏差。 | 

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