Bootstrap

第十一篇 SQL高级处理:窗口函数和GROUPING运算符,看这篇就够了

目录

    • 1. 窗口函数:像班级排名一样分析数据
      • 1.1 什么是窗口函数?
      • 1.2 三大排名函数对比(附生活案例)
      • 1.3 累计统计:你的工资今年涨了多少?
      • 1.4 移动平均:预测股票走势的秘密武器
    • 2. GROUPING运算符:自动生成Excel式合计行
      • 2.1 ROLLUP:自动加小计和总计
      • 2.2 CUBE:所有维度组合统计
      • 2.3 GROUPING SETS:只生成我需要的统计
    • 3. 实战技巧+避坑指南
      • ✅ 必看技巧
      • ⚠️ 常见错误
    • 4. 互动问答+学习资源
      • 🤔 小测验(答案见评论区)
        • 测试数据表
        • 题目1:计算每个学生的成绩比前一名高多少分
        • 题目2:ROLLUP和CUBE的区别是什么?
      • 📚 推荐学习资源

1. 窗口函数:像班级排名一样分析数据

1.1 什么是窗口函数?

想象你有一张全班成绩表,要回答这些问题:

  • 王同学在班里排第几?(排名)
  • 他比前一名高多少分?(差值)
  • 他的成绩占全班总分多少比例?(占比)

如果用普通SQL,需要多次查询+临时表。而窗口函数就像给你的数据开了一个"滑动窗口",直接在一行里算出这些复杂结果!

-- 基础语法(重点记这个!)
SELECT 
    <>,
    RANK() OVER (PARTITION BY 班级 ORDER BY 成绩 DESC) AS 排名
FROM 成绩表;

1.2 三大排名函数对比(附生活案例)

函数特点生活案例
RANK()并列跳号(1,1,3)奥运奖牌:金牌两人,下个是铜牌
DENSE_RANK()并列不跳号(1,1,2)考试排名:两人并列第一,下个第二
ROW_NUMBER()强制连续序号(1,2,3)电影院座位号:必须连续

代码示例:

-- 按商品价格排名
SELECT 
    product_name,
    price,
    RANK() OVER (ORDER BY price DESC) AS '跳位排名',
    DENSE_RANK() OVER (ORDER BY price DESC) AS '不跳位排名',
    ROW_NUMBER() OVER (ORDER BY price DESC) AS '强制连续排名'
FROM products;

1.3 累计统计:你的工资今年涨了多少?

场景:计算每个月的工资累计值(类似支付宝年度账单)

SELECT 
    month,
    salary,
    SUM(salary) OVER (ORDER BY month) AS '累计工资'
FROM salary_table;

输出效果:

monthsalary累计工资
11000010000
21100021000
31200033000

1.4 移动平均:预测股票走势的秘密武器

场景:计算近3天的平均股价(平滑波动)

SELECT
    date,
    stock_price,
    AVG(stock_price) OVER (
        ORDER BY date 
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS '3日移动平均'
FROM stock_data;

效果解释:

  • 2023-01-03的均值 = (01价格 + 02价格 + 03价格)/3
  • 2023-01-04的均值 = (02价格 + 03价格 + 04价格)/3

2. GROUPING运算符:自动生成Excel式合计行

2.1 ROLLUP:自动加小计和总计

场景:统计每个部门的薪资,并自动生成部门小计和公司总计

SELECT 
    COALESCE(department, '公司总计') AS 部门,
    SUM(salary) AS 总工资
FROM employees
GROUP BY ROLLUP(department);

输出结果:

研发部    500000
销售部    300000
公司总计  800000

2.2 CUBE:所有维度组合统计

场景:同时按部门和职级统计工资,生成所有可能的组合

SELECT 
    department,
    job_level,
    SUM(salary)
FROM employees
GROUP BY CUBE(department, job_level);

生成组合包括:

  • 各部门各职级
  • 各部门总计
  • 各职级总计
  • 公司总计

2.3 GROUPING SETS:只生成我需要的统计

场景:只想要部门总计和职级总计,不要其他组合

SELECT 
    department,
    job_level,
    SUM(salary)
FROM employees
GROUP BY GROUPING SETS ((department), (job_level));

3. 实战技巧+避坑指南

✅ 必看技巧

  1. 性能优化:窗口函数中ORDER BY的列尽量有索引
  2. 框架范围
    • ROWS BETWEEN ...:按物理行数
    • RANGE BETWEEN ...:按逻辑值范围
  3. 处理NULL值:用COALESCE()替换分组产生的NULL

⚠️ 常见错误

-- 错误!窗口函数不能直接用在WHERE中
SELECT name, RANK() OVER(...) 
FROM table 
WHERE RANK() <= 3; -- 报错!

-- 正确做法:用子查询
SELECT * FROM (
    SELECT name, RANK() OVER(...) AS rk
    FROM table
) WHERE rk <= 3;

4. 互动问答+学习资源

🤔 小测验(答案见评论区)

测试数据表
-- 学生成绩表(students)
CREATE TABLE students (
    student_id INT PRIMARY KEY,
    name VARCHAR(50),
    class VARCHAR(20),  -- 班级
    score INT           -- 考试成绩
);

INSERT INTO students VALUES
(1, '张三', 'A班', 85),
(2, '李四', 'A班', 90),
(3, '王五', 'B班', 78),
(4, '赵六', 'B班', 78),
(5, '陈七', 'B班', 92);

题目1:计算每个学生的成绩比前一名高多少分

要求:按班级分组,按成绩降序排名,并显示与前一名成绩的差值。
提示:使用 LAG() 窗口函数

题目2:ROLLUP和CUBE的区别是什么?

要求:用一句话说明两者差异,并举例说明。

📚 推荐学习资源

  1. 图书:《SQL进阶教程》MICK著
  2. 在线练习:SQLZoo窗口函数练习
  3. 视频:B站窗口函数实战

🎉 恭喜!你已经掌握了SQL高级处理的核心技能!

🎯下期预告:《通过应用程序连接数据库》
💬互动话题:你在学习SQL时遇到过哪些坑?欢迎评论区留言讨论!
🏷️温馨提示:我是[随缘而动,随遇而安], 一个喜欢用生活案例讲技术的开发者。如果觉得有帮助,点赞关注不迷路🌟


;