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

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


相关推荐
松涛和鸣16 分钟前
72、IMX6ULL驱动实战:设备树(DTS/DTB)+ GPIO子系统+Platform总线
linux·服务器·arm开发·数据库·单片机
likangbinlxa33 分钟前
【Oracle11g SQL详解】UPDATE 和 DELETE 操作的正确使用
数据库·sql
r i c k1 小时前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦1 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL2 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·2 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
野生技术架构师2 小时前
SQL语句性能优化分析及解决方案
android·sql·性能优化
IT邦德2 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫3 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写