Hive窗口分析函数(案例详细讲解)

本文详细介绍了Hive窗口函数的语法结构、Over从句、分析函数,以及RANK、DENSE_RANK、ROW_NUMBER、NTILE等常见函数的用法,并通过案例展示了如何进行数据计算,包括求和、排名、分组切片等操作。此外,还讲解了LAG、LEAD、FIRST_VALUE、LAST_VALUE等函数的应用,帮助理解窗口函数在数据处理中的重要作用。

一、语法结构

  • 语法结构分析函数 over(partition by 列名 order by 列名 rows between 开始位置 and 结束位置)
  • over()函数中包括三个函数:包括分区partition by 列名排序order by 列名、指定窗口范围rows between 开始位置 and 结束位置
  • 我们在使用over()窗口函数时,over()函数中的这三个函数可组合使用也可以不使用。
    over()函数中如果不使用这三个函数,窗口大小是针对查询产生的所有数据,如果指定了分区,窗口大小是针对每个分区的数据。

二、窗口函数

  • ① LEAD(col,n,DEFAULT)

    • 用于统计窗口内往下第n行值
    • 第一个参数为列名,第二个参数为往下第n行(可选,默认为1),第三个参数为默认值(当往下第n行为NULL时候,取默认值,如不指定,则为NULL)。
  • ② LAG(col,n,DEFAULT)

    • 用于统计窗口内往上第n行值
    • 第一个参数为列名,第二个参数为往上第n行(可选,默认为1),第三个参数为默认值(当往上第n行为NULL时候,取默认值,如不指定,则为NULL)
  • ③ FIRST_VALUE

    • 取分组内排序后,截止到当前行,第一个值
  • ④ LAST_VALUE

    • 取分组内排序后,截止到当前行,最后一个值

三、Over从句

  • 1.使用标准的聚合函数COUNT、SUM、MIN、MAX、AVG

  • 2.使用PARTITION BY语句,使用一个或者多个原始数据类型的列

  • 3.使用PARTITION BY与ORDER BY语句,使用一个或者多个数据类型的分区或者排序列

  • 4.使用窗口规范,窗口规范支持以下格式:

    (ROWS | RANGE) BETWEEN (UNBOUNDED | [num]) PRECEDING AND ([num] PRECEDING | CURRENT ROW | (UNBOUNDED | [num]) FOLLOWING)
    (ROWS | RANGE) BETWEEN CURRENT ROW AND (CURRENT ROW | (UNBOUNDED | [num]) FOLLOWING)
    (ROWS | RANGE) BETWEEN [num] FOLLOWING AND (UNBOUNDED | [num]) FOLLOWING
    
  • 5.窗口范围说明:

    我们常使用的窗口范围是ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(表示从起点到当前行),常用该窗口来计算累加。

    PRECEDING:往前
    FOLLOWING:往后
    CURRENT ROW:当前行
    UNBOUNDED:起点(一般结合PRECEDING,FOLLOWING使用)
    UNBOUNDED PRECEDING表示该窗口最前面的行(起点)
    UNBOUNDED FOLLOWING:表示该窗口最后面的行(终点)

    比如说:
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(表示从起点到当前行)
    ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING(表示往前2行到往后1行)
    ROWS BETWEEN 2 PRECEDING AND CURRENT ROW(表示往前2行到当前行)
    ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING(表示当前行到终点)

    ORDER BY后面缺少窗口从句条件(即 分析函数 over(partition by 列名 order by 列名) ),窗口规范默认是 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

    ORDER BY和窗口从句都缺失(即分析函数 over(partition by 列名)), 窗口规范默认是 ROW BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

    注意:OVER从句支持以下函数, 但是并不支持和窗口一起使用它们:
    Ranking函数: Rank, NTile, DenseRank, CumeDist, PercentRank.
    LeadLag函数(即 Ranking函数 不能和 LeadLag函数一起使用)

四、分析函数

  • RANK:从1开始,按照顺序按照值排序时产生一个自增编号,值相等时会重复会产生空位(如:1、2、3、3、3、6)

  • ROW_NUMBER:从1开始,按照顺序,按照值排序时产生一个自增编号,不会重复(如:1、2、3、4、5、6)

  • DENSE_RANK:从1开始,按照值排序时产生一个自增编号,值相等时会重复,不会产生空位(如:1、2、3、3、3、4)

  • CUME_DIST:小于等于当前值的行数/分组内总行数。比如,统计小于等于当前薪水的人数,所占总人数的比例

  • PERCENT_RANK:分组内当前行的RANK值-1/分组内总行数-1

  • NTILE(n):用于将分组数据按照顺序切分成n片,返回当前切片值,如果切片不均匀,默认增加第一个切片的分布。NTILE不支持ROWS BETWEEN,比如 NTILE(2) OVER(PARTITION BY cookieid ORDER BY createtime ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)

  • Distinct: 去重。如COUNT(DISTINCT a) OVER (PARTITION BY c)

五、COUNT、SUM、MIN、MAX、AVG

本小节主要讲解COUNT、SUM、MIN、MAX、AVG的用法。

1.数据准备
-------------------------------------------------------------------------
//订单表order : name, order_date, cost
Jan,2020-01-01,87
Jan,2020-01-02,95
Jan,2020-03-03,68
Jan,2020-05-01,68
Ben,2020-04-01,94
Ben,2020-01-02,56
Ben,2020-04-03,84
Ben,2020-05-01,84
Dan,2020-02-01,64
Dan,2020-03-02,86
Dan,2020-04-03,84
Dan,2020-04-01,84
Tim,2020-03-01,65
Tim,2020-02-02,85
Tim,2020-01-03,78
Tim,2020-04-01,78
Bob,2020-02-01,67
Bob,2020-03-02,95
Bob,2020-04-03,70
Bob,2020-05-01,70
------------------------------------------------------------------------
create table order_test(
	name string,
	order_date string, 
	cost int) 
row format delimited fields terminated by ',';
-------------------------------------------------------------------------
load data local inpath '/tmp/order.txt' into table order;
2.sql示例
//COUNT、SUM、MIN、MAX、AVG
//以 sum函数举例
select 
	name, 
	order_date, 
	cost,
	
	--over():所有的数据求和。sum_01是一样的。
	--求和范围:order_test表的所有数据
	sum(cost) over() as sum_01,
	
	--over(partition by) :按照name分组,对分组相加。组内的sum_02是一个值。
	--求和范围:以name分组,每个组内求和
	sum(cost) over(partition by name) as sum_02,
	
	--over(parition by order by):按照name分组,对分组按照时间升序累加。组内sum_03是一个变化的累加值
	--求和范围:默认为从起点到当前行。以name分组,每个组内按order_date累计求和。注意和②的区别
	sum(cost) over(partition by name order by order_date) as sum_03,
	
	--④ between unbounded preceding and current row : 同③,从起点到当前行。(order by 省略窗口范围的默认范围)
	sum(cost) over(partition by name order by order_date rows between unbounded preceding and current row) as sum_04,
	
	--⑤ rows between n preceding and current row: 以name分组,当前行和前面n行做聚合。聚合的行数为: n+1(当前行)。 示例为 n=1的情况
	sum(cost) over(partition by name order by order_date rows between 1 preceding and current row) as sum_05,

	--⑥ rows between n1 preceding and n2 following:以name分组,当前行 + 前n1行 +后n2行做聚合。聚合的行数为:n1+n2+1(当前行) 示例n1 n2 =1
	sum(cost) over(partition by name order by order_date rows between 1 preceding and 1 following) as sum_06,
	
	--⑦rows between current row and unbounded following:以name分组,当前行+后面的所有行
	sum(cost) over(partition by name order by order_date rows between current row and unbounded following) as sum_07

from  order_test;

执行上面的sql:

select 
    name, 
    order_date, 
    cost,
    
    sum(cost) over() as sum_01,

    sum(cost) over(partition by name) as sum_02,
    
    sum(cost) over(partition by name order by order_date) as sum_03,
    
    sum(cost) over(partition by name order by order_date rows between unbounded preceding and current row) as sum_04,
    
    sum(cost) over(partition by name order by order_date rows between 1 preceding and current row) as sum_05,

    sum(cost) over(partition by name order by order_date rows between 1 preceding and 1 following) as sum_06,
    
    sum(cost) over(partition by name order by order_date rows between current row and unbounded following) as sum_07

from  order_test;	

查询结果如下:

name	order_date	   cost    sum_01  sum_02  sum_03  sum_04  sum_05  sum_06  sum_07

Ben     2020-01-02      56      1562    318     56      
<think>嗯,用户想了解Hive窗口函数的概念和用法。从用户提问的措辞来看,ta应该是刚接触这个概念,需要清晰的框架性说明和具体案例。用户提到了"使用说明"和"示例",说明ta更关注实用价值而非底层原理。之前系统给出的引用材料质量很高,覆盖了窗口函数的核心要点:基础语法结构、分区与排序机制、窗口帧模式,还贴心地列出了三类窗口函数的区别。不过引用内容有点零散,需要我重新整合成逻辑连贯的讲解。特别要注意用户可能存在的认知盲点:1.容易混淆窗口函数和聚合函数(比如GROUPBY)2.不理解窗口帧动态变化特性3.对物理窗口(ROWS)和逻辑窗口(RANGE)的区别模糊我打算这样组织回答:先用仓库货架的比喻建立直观认知(就像引用2提到的窗口概念),这是技术人员容易理解的场景。重点强调OVER()子句这个核心载体——很多初学者会忽略空括号也是合法语法(表示全表窗口),这点引用3也提到了。然后拆解OVER()的三大组件时,要突出易错点:-PARTITIONBY虽类似GROUPBY但不聚合行数(引用4明确指出结果集行数不变)-ORDERBY在移动窗口中的关键作用(引用1提到这是windowclause的前置条件)-窗口帧部分用阶梯图示意边界值会更直观示例部分优先选业务通用场景:销售统计最适合演示基础功能(SUM+ORDERBY做累计),员工薪资排名能自然引出RANK系的区别(引用4详细解释了这三个易混函数)。考虑到用户可能实际操作,每个SQL都准备可粘贴的字段占位符。最后用动态TOP3问题带出高级窗口帧的用法,顺便暗示"可无限拓展"的学习空间。安全问题方面:所有示例数据都用虚拟值,避免涉及真实业务字段。</think> ### Hive窗口函数使用说明与示例 窗口函数Hive中用于**在特定数据子集(窗口)内进行行级计算**的高级功能,不改变原始结果集行数,常用于排名、累积计算等场景。核心语法如下: ```sql function() OVER ( [PARTITION BY 分组字段] [ORDER BY 排序字段 [ASC|DESC]] [ROWS/RANGE BETWEEN 起始位置 AND 结束位置] ) ``` #### **关键组成部分解析** 1. **`PARTITION BY`**(可选) - 将数据按指定字段分组,函数独立作用于每个分组 - 例:`PARTITION BY dept` → 按部门分组计算 2. **`ORDER BY`**(可选) - 定义窗口内数据的排序方式,决定计算逻辑的顺序 - 例:`ORDER BY salary DESC` → 按工资降序排列 3. **窗口帧定义**(`ROWS`/`RANGE`) - `ROWS`: 基于**物理行位置**(如:前2行后2行) - `RANGE`: 基于**逻辑值范围**(如:数值相差10以内的行) - 常用范围: - `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` → 从分组首行到当前行 - `ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING` → 当前行前一行+当前行+后一行 --- #### **常用窗口函数分类与示例** ##### **1. 排序函数** | 函数 | 特点 | 示例场景 | |---------------------|------------------------------|--------------------------| | `ROW_NUMBER()` | 相同值顺序编号(1,2,3,...) | 员工工资部门内排名 | | `RANK()` | 相同值同排名,跳过后续序号 | 学生成绩并列第二名 | | `DENSE_RANK()` | 相同值同排名,不跳号(1,1,2) | 销售额相同商品连续排名 | **示例**:部门内薪资排名 ```sql SELECT employee_id, dept, salary, ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn, RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS rk, DENSE_RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS dr FROM employees; ``` 输出: | employee_id | dept | salary | rn | rk | dr | |-------------|------|--------|----|----|----| | 101 | IT | 9000 | 1 | 1 | 1 | | 102 | IT | 8500 | 2 | 2 | 2 | | 103 | IT | 8500 | 3 | 2 | 2 | *RANK跳过3,DENSE_RANK不跳* --- ##### **2. 聚合函数窗口化使用)** ```sql -- 计算每个员工的累计薪资(从入职首月到当前月) SELECT employee_id, month, salary, SUM(salary) OVER ( PARTITION BY employee_id ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS cumulative_salary FROM salary_records; ``` --- ##### **3. 分析函数** - **`LAG(col, n)`**: 获当前行**前n行**的数据 - **`LEAD(col, n)`**: 获当前行**后n行**的数据 ```sql -- 对比员工本月与上月工资 SELECT employee_id, month, salary, LAG(salary, 1) OVER (PARTITION BY employee_id ORDER BY month) AS prev_salary FROM salary_records; ``` --- #### **高级窗口帧示例:动态TOP N** ```sql -- 筛选每个部门薪资前3的员工 SELECT * FROM ( SELECT employee_id, dept, salary, ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn FROM employees ) tmp WHERE rn <= 3; ``` --- #### **常见问题解答** 1. **窗口函数 vs GROUP BY?** - `GROUP BY`聚合后**行数减少**,窗口函数**保留所有原始行**,仅添加计算结果列[^4]。 2. **省略`PARTITION BY`或`ORDER BY`?** - 省略`PARTITION BY` → **全表视为单个窗口** - 省略`ORDER BY` → 窗口帧默认为`ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING`(整个分区) 3. **`RANGE`与`ROWS`区别?** - `ROWS`按**实际行偏移**(如前后2行) - `RANGE`按**字段值偏移**(如 `RANGE BETWEEN 100 PRECEDING AND 200 FOLLOWING` → 值在[当前值-100, 当前值+200]的行) > 官方文档建议:若需要精确物理行控制用`ROWS`,需逻辑值范围用`RANGE`[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值