【SQL】SQL-常见窗口函数有哪些-上篇

【SQL】SQL-常见窗口函数有哪些-上篇

一、引言

今天来聊聊 Hive 里窗口函数的应用场景,原来大家对SQL这么感兴趣,阅读比Python高好多.orz

【窗口函数,绝对SQL进阶的关键门槛。SQL 水平能否上一个台阶,除了思维,更重要的是高效运用窗口函数。】

很多同学写聚合查询时只会 GROUP BY其实窗口函数才是真爱啊,这个浮躁的社会。

窗口既能分组聚合,又不会丢失明细数据,还能轻松实现排名、累计、同比等高阶分析,妥妥的。

Hive 从 2.0 开始支持窗口函数,咱们先讲上篇------聚合类窗口函数排名类窗口函数,配合实战解析,保证你看完就能用上。


二、窗口函数基础概念

在正式讲之前,先搞清楚几个关键概念,窗口函数的基础:

概念 说明 示例
OVER() 窗口函数的声明,定义计算窗口 SUM(col) OVER(...)
PARTITION BY 分区,类似 GROUP BY,但保留明细 按部门分组统计
ORDER BY 窗口内排序,决定计算顺序 按时间正序
ROWS BETWEEN 窗口边界,控制参与计算的行 往前3行~当前行
sql 复制代码
-- 窗口函数基本语法
SELECT 
    SUM(column) OVER( PARTITION BY col1, col2  -- 可选:分区
    ORDER BY col3            -- 可选:排序
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW  -- 可选:窗口边界
) AS 窗口函数基本语法

是不是看着很难理解?没事,确实也不简单,orz...慢慢来~


三、聚合类窗口函数(理解了,前面都是坦途!)

1. SUM 累计求和

基础用法

sql 复制代码
-- 简单累计:所有数据求和
SELECT
    name,
    score,
    SUM(score) OVER() AS 总分
FROM student_scores;

划重点:OVER() 不带任何参数时,窗口是全部数据,等同于 GROUP BY 的聚合效果,但保留每行明细。

带分区累计

sql 复制代码
-- 按班级分组计算累计
SELECT
    class,
    name,
    score,
    SUM(score) OVER(PARTITION BY class) AS 班级总分,
    ROUND(score * 100.0 / SUM(score) OVER(PARTITION BY class), 2) AS 班级占比
FROM student_scores;

带排序的滑动窗口

sql 复制代码
-- 按时间顺序累计(滚动求和)
SELECT
    dt,
    sales,
    SUM(sales) OVER(ORDER BY dt ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 累计销售额
FROM daily_sales
ORDER BY dt;

划重点:ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 表示从第一行到当前行,这是滑动窗口求累计的标配写法。


2. AVG 平均值

sql 复制代码
-- 计算每人的平均月度消费
SELECT
    user_id,
    month,
    consumption,
    AVG(consumption) OVER(PARTITION BY user_id ORDER BY month ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS 近3月平均   -- 包含当前月和前2个月
FROM user_consumption
ORDER BY user_id, month;

划重点:滑动窗口 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW 实现了"近3个月平均"的效果,比 GROUP BY 灵活多了。


3. COUNT 计数

sql 复制代码
-- 统计每笔订单之后还有多少笔订单   是不是比你们写一堆的LEFT JOIN 省力多了?
SELECT
    order_id,
    create_time,
    amount,
    COUNT(*) OVER( ORDER BY create_time ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS 后续订单数   -- 当前行之后所有行
FROM orders
ORDER BY create_time;

四、排名类窗口函数(面试有笔试的话,必考!)

1. ROW_NUMBER / RANK / DENSE_RANK 详解

这三个函数都是排名,但有区别:

函数 特点 示例(同样是1,2,2,3)
ROW_NUMBER 连续不重复编号 1, 2, 3, 4
RANK 并列跳号 1, 2, 2, 4
DENSE_RANK 并列不跳号 1, 2, 2, 3
sql 复制代码
-- 对比三种排名
SELECT
    name,
    score,
    ROW_NUMBER() OVER(ORDER BY score DESC) AS 行号,
    RANK() OVER(ORDER BY score DESC)       AS 普通排名,
    DENSE_RANK() OVER(ORDER BY score DESC) AS 紧凑排名
FROM student_scores
ORDER BY score DESC;

输出示例:

复制代码
name | score | 行号 | 普通排名 | 紧凑排名
张三 | 95    | 1    | 1        | 1
李四 | 90    | 2    | 2        | 2
王五 | 90    | 3    | 2        | 2
赵六 | 85    | 4    | 4        | 3

划重点:分数相同时,ROW_NUMBER 给不同编号,RANK 编号相同但下一个跳号,DENSE_RANK 编号相同且下一个不跳号。


2. 实战:班级内排名

sql 复制代码
-- 给每个班级的学生按成绩排名
SELECT
    class,
    name,
    score,
    ROW_NUMBER() OVER(PARTITION BY class ORDER BY score DESC) AS 班级排名,
    RANK() OVER(PARTITION BY class ORDER BY score DESC)       AS 班级排名_并列
FROM student_scores
ORDER BY class, 班级排名;

3. 实战:筛选TopN

sql 复制代码
-- 取出每个班级成绩前3名
SELECT *
FROM (
    SELECT
        class,
        name,
        score,
        ROW_NUMBER() OVER(PARTITION BY class ORDER BY score DESC) AS rn
    FROM student_scores
) t
WHERE rn <= 3;

划重点:窗口函数不能直接在 WHERE 里用,得套一层子查询来实现筛选。


4. 实战:连续出现N次 -- 【连续一出,面试基本能挂掉90%的人】

sql 复制代码
-- 找出连续3天以上活跃的用户
WITH user_active AS (
    SELECT DISTINCT
        user_id,
        dt
    FROM user_log
)
SELECT
    user_id,
    MIN(dt) AS 连续开始,
    MAX(dt) AS 连续结束,
    COUNT(*) AS 连续天数
FROM (
    SELECT
        user_id,
        dt,
        -- 把不连续的日期分组
        dt - ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY dt) * 1 AS grp
    FROM user_active
) t
GROUP BY user_id, grp
HAVING COUNT(*) >= 3
ORDER BY user_id, 连续开始;

这是经典的"连续天数"问题解法:通过 dt - rn 把连续日期归到同一组。


五、总结对比

函数类别 常用函数 典型场景
聚合类 SUM, AVG, COUNT, MAX, MIN 累计、占比、滑动平均
排名类 ROW_NUMBER, RANK, DENSE_RANK 名次、TopN、连续天数

怎么样,窗口函数很好用吧~!关键是理解、属于数据结构中,如何构建结构的空间思维。

下篇预告: 偏移类窗口函数(LAG/LEAD/FIRST_VALUE/LAST_VALUE)以及综合实战案例,敬请期待!

今天的分享就到这里,觉得有用动动小手点赞+关注+收藏,一键三连~ 有问题留言沟通啦~

相关推荐
m0_596749098 小时前
JavaScript中手动实现一个new操作符的底层逻辑
jvm·数据库·python
多加点辣也没关系8 小时前
Redis 的安装(详细教程)
数据库·redis·缓存
数据库小学妹9 小时前
数据库连接池避坑指南:告别“连接超时”与“资源耗尽”,让系统跑得更快!
数据库·redis·sql·mysql·缓存·dba
dishugj9 小时前
HANA 数据库备份与恢复
数据库·oracle
前进的李工9 小时前
EXPLAIN输出格式全解析:JSON、TREE与可视化
开发语言·数据库·mysql·性能优化·explain
达梦产品与服务9 小时前
稳扎稳打,持续迭代 | SQLark V3.10 更新,30+ 项优化与修复
mysql·oracle·达梦数据库·pg·sqlark百灵连接
難釋懷10 小时前
Redis网络模型-IO多路复用模型-poll模式
网络·数据库·redis
dFObBIMmai10 小时前
如何在 CSS 中实现元素的绝对定位,使其不受窗口尺寸变化影响
jvm·数据库·python
treesforest10 小时前
IP精准定位服务:从城市轮廓到街道坐标,技术如何重塑空间感知
网络·数据库·网络协议·tcp/ip·ip
大明者省10 小时前
宝塔开了端口,Ubuntu 还得开相应端口才能打通
服务器·数据库·ubuntu