【大数据之Hive】十六、Hive-HQL函数之窗口函数(开窗函数)

news2024/9/27 17:31:58

1 概述

  先定义了窗口的大小(按行来算),然后对窗口内的行的数据进行计算,再将计算结果返回给改行。
在这里插入图片描述
  窗口函数包括窗口和函数两部分,窗口用于定义计算范围,函数用于定义计算逻辑,窗口函数只会在原来的表上增加一列结果列,不改变原来的数据。

1.1 窗口函数使用语法

--窗口函数使用语法
select
    ...,
    函数(col_name) over (窗口范围) result_col_name   -表示在窗口范围之上应用函数逻辑
from table_name;

函数:
  绝大多数聚合函数都可以配合窗口使用,如max(),min(),sum(),count(),avg()等。

窗口:
  分为两种,一种是基于行的,一种是基于值的。
  基于行的:如每行数据的窗口为上一行到当前行:对于第1行来说,处于窗口内的行为第0行和第1行;对于第2行来说,处于窗口内的行为第1、2行。
  基于值的:如要求每行数据的窗口值位于当前值-1到当前值:对于值为1的数据来说,窗口范围的值为[1-1,1]即[0,1],此时只有1行数据;对于值为2的数据来说,窗口范围的值为[2-1,2]即[1,2],有第1、2、3行数据。
在这里插入图片描述

1.2 窗口语法(基于行row)

  基于真正运算时的行,并不是基于看到的表数据,所以需要声明一个排序字段 order by ,在真正进行窗口计算时使用哪个窗口进行排序。

--基于行
函数(col_name) over (窗口范围) result_col_name

--窗口范围(写在over后面的括号里):
order by [col_name] rows between ***1 and ***2

***1(窗口的起点):unbounded preceding / [num] preceding / current row / [num] following
***2(窗口的终点):
    对于 unbounded preceding / [num] preceding 来说,终点可以写为 [num] preceding / current row / [num] following / unbounded following
    对于 current row 来说,终点可以写为 current row / [num] following / unbounded following
    对于 [num] following 来说,终点可以写为 [num] following / unbounded following

(1)窗口起点(可以不包含当前行):
(1)unbounded preceding:无边界的,可以理解为负无穷,表示表起点的第一行。
(2)[num] preceding:num为数字,表示当前行的前 num 行作为起点。
(3)current row:起点为当前行。
(4)[num] following:表示当前行的后 num 行作为起点。

(2)窗口终点(取决于起点方式):
(1)[num] preceding:当前行的前 num 行作为终点;当起点和终点都用 [num] preceding 时,起点的num值要比终点的大,保证终点在起点后面。
(2)current row:当前行作为终点。
(3)[num] following:当前行的后 num 行作为终点;当起点和终点都用 [num] following 时,起点的num值要小于终点的num值,保证终点在起点后面。
(4)unbounded following:相当于正无穷,表示表里的最后一行作为终点。

例如:
在这里插入图片描述
上述例子可以理解为统计从历史到当前的每一个订单的销售额。

1.3 窗口语法(基于值range)

  基于值的 order by 表示指定哪个字段的值进行划分窗口,当使用 [num] preceding 和 [num] following 时使用的字段必须是整数类型(否则窗口划分失效) 。

--基于值
函数(col_name) over (窗口范围) result_col_name

--窗口范围(写在over后面的括号里):
order by [col_name] range between ***1 and ***2

***1(窗口的起点):unbounded preceding / [num] preceding / current row / [num] following
***2(窗口的终点):
    对于 unbounded preceding / [num] preceding 来说,终点可以写为 [num] preceding / current row / [num] following / unbounded following
    对于 current row 来说,终点可以写为 current row / [num] following / unbounded following
    对于 [num] following 来说,终点可以写为 [num] following / unbounded following

(1)窗口起点(可以不包含当前行):
(1)unbounded preceding:无边界的,可以理解为负无穷。
(2)[num] preceding:num为数字,表示当前值 减num 的值作为起点。
(3)current row:起点为当前值。
(4)[num] following:表示当前值 加num 的值作为起点。

(2)窗口终点(取决于起点方式):
(1)[num] preceding:当前值 减num 的值作为终点;当起点和终点都用 [num] preceding 时,起点的num值要比终点的大,保证终点在起点后面。
(2)current row:当前值作为终点。
(3)[num] following:当前值 加num 的值作为终点;当起点和终点都用 [num] following 时,起点的num值要小于终点的num值,保证终点在起点后面。
(4)unbounded following:相当于正无穷。

例如:
在这里插入图片描述

1.4 窗口语法(分区)

  在定义窗口范围时,指定分区字段,可以对每个分区进行单独划分窗口。使用 partition by 进行分区。

--分区,在分区之后再使用基于行或基于值的窗口范围定义
函数(col_name) over (窗口范围) result_col_name

--窗口范围(写在over后面的括号里):
partition by col_name order by [col_name] range/rows between ***1 and ***2

***1(窗口的起点):unbounded preceding / [num] preceding / current row / [num] following
***2(窗口的终点):
    对于 unbounded preceding / [num] preceding 来说,终点可以写为 [num] preceding / current row / [num] following / unbounded following
    对于 current row 来说,终点可以写为 current row / [num] following / unbounded following
    对于 [num] following 来说,终点可以写为 [num] following / unbounded following

例如:
在这里插入图片描述
上述例子可以理解为每个用户截至到每次下单时间的历史下单总额。

1.5 窗口语法(缺省)

  over() 中的三部分内容 partition by、order by、rows/range between … and … 都可以省略不写。

(1)partition by 省略表示不分区。

(2)order by 省略表示不排序;基本上使用 rows 和 range 都需要写 order by ;使用 rows 时不写 order by 即表示不声明排序,使用随机的顺序;使用 range 时不写 order by 则表示窗口划分为负无穷到正无穷。

(3)rows/range between … and … 省略则使用默认值:
  (i)如果 over() 中包含 order by 则默认:range between unbounded preceding and current row (即第一行到当前行)。
  (ii)如果 over() 中不包含 order by 则默认:rows between unbounded preceding and unbounded following (即第一行到最后一行)。

2 常用窗口函数

  分为聚合函数、跨行取值函数、排名函数。

2.1 聚合函数

max()、min()、sum()、avg()、count()。

2.2 跨行取值函数

(1)lead和lag
  功能:获取当前行的**上面(lag)下面(lead)**的某行、某个字段的值。
  lead和lag函数不支持自定义窗口,即不能用rows或range。

语法:

select
    ...,
    lag(col_name,偏移量(数字,指上面哪行),默认值(用于取不到时)) over (partition by col_name order by col_name) result_last_col_name,
    lead(col_name,偏移量(数字,指下面哪行),默认值(用于取不到时)) over (partition by col_name order by col_name) result_next_col_name
from table_name;

在这里插入图片描述

(2)first_value和last_value

  功能:获取窗口内某一列的第一个或最后一个值。允许自定义窗口。

语法:

select
    ...,
    first_value(col_name,true/false(是否要跳过null)) over (partition by col_name order by col_name) result_first_col_name,
    last_value(col_name,true/false(是否要跳过null)) over (partition by col_name order by col_name) result_last_col_name
from table_name;

在这里插入图片描述

2.3 排名函数

常用排名函数(排名函数不支持自定义窗口):
(1)rank():考虑并列,稀疏排名,如1 1 3
(2)dense_rank():考虑并列,密集排名,如1 1 2
(3)row_number():不考虑比列,如1 2 3

语法:

select 
    ...,
    rank() over (partition by col_name order by col_name asc/desc) result_rk_col_name,
    dense_rank() over (partition by col_name order by col_name asc/desc) result_dense_rk_col_name,
    row_number() over (partition by col_name order by col_name asc/desc) result_rn_col_name
from table_name;

在这里插入图片描述

3 案例

数据准备:
表结构:
在这里插入图片描述

--建表
create table order_info
(
   order_id string,    --订单id
   user_id string,    -- 用户id
   user_name string,    -- 用户姓名
   order_date string,    -- 下单日期
   order_amount int    -- 订单金额
)
row format delimited fields terminated by '\t';

--插入数据
insert overwrite table order_info
values ('1', '1001', '小元','2022-01-01',10),
      ('2', '1002', '小海', '2022-01-02',15),
      ('3', '1001', '小元', '2022-02-03',23),
      ('4', '1002', '小海', '2022-01-04',29),
      ('5', '1001', '小元', '2022-01-05',46),
      ('6', '1001', '小元', '2022-04-06',42),
      ('7', '1002', '小海', '2022-01-07',50),
      ('8', '1001', '小元', '2022-01-08',50),
      ('9', '1003', '小辉', '2022-04-08',62),
      ('10', '1003', '小辉', '2022-04-09',62),
      ('11', '1004', '小猛', '2022-05-10',12),
      ('12', '1003', '小辉', '2022-04-11',75),
      ('13', '1004', '小猛', '2022-06-12',80),
      ('14', '1003', '小辉', '2022-04-13',94);

需求及实现:

--统计每个用户截至每次下单的累积下单总额:order_id user_id user_name order_date order_amount sum_so_far
select
    order_id,
    user_id,
    user_name,
    order_date,
    order_amount,
    sum(order_amount) over (partition by user_id 
                            order by order_date rows between unbounded preceding and current row) sum_so_far
from order_info;

--统计每个用户截至每次下单的当月累积下单总额:order_id user_id user_name order_date order_amount sum_so_far
select
    order_id,
    user_id,
    user_name,
    order_date,
    order_amount,
    sum(order_amount) over (partition by user_id,substring(order_date,1,7) 
                            order by order_date rows between unbounded preceding and current row) sum_so_far
from order_info;


--统计每个用户每次下单距离上次下单相隔的天数(首次下单按0天算):order_id user_id user_name order_date order_amount diff
select
    order_id,
    user_id,
    user_name,
    order_date,
    order_amount,
    datediff(order_date,lag(order_date,1,order_date)) over (partition by user_id order by order_date) diff
from order_info;

select
   order_id,
   user_id,
   user_name,
   order_date,
   order_amount,
   datediff(order_date,last_order_date) diff
from
(
   select
       order_id,
       user_id,
       user_name,
       order_date,
       order_amount,
       lag(order_date,1,order_date) over(partition by user_id order by order_date)last_order_date
   from order_info
)t1;

--查询所有下单记录以及每个用户的每个下单记录所在月份的首/末次下单日期:order_id user_id user_name order_date order_amount first_date last_date
select
    order_id,
    user_id,
    user_name,
    order_date,
    order_amount,
    first_value(order_date,false) over (partition by user_id,substring(order_date,1,7) order by order_date) first_date,
    last_value(order_date,false) over (partition by user_id,substring(order_date,1,7) order by order_date
                                       rows between unbounded preceding and unbounded following) last_date
from order_info;

--为每个用户的所有下单记录按照订单金额进行排名:order_id user_id user_name order_date order_amount rk drk rn
select
    order_id,
    user_id,
    user_name,
    order_date,
    order_amount,
    rank() over (partition by user_id order by order_amount desc) rk,
    dense_rank() over (partition by user_id order by order_amount desc) drk,
    row_number() over (partition by user_id order by order_amount desc) rn
from order_info;
--rank()dense_rank()row_number()可以解决分组topN问题,配合where使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/688530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

React通过useContext特性实现组件数据传递

我们来说一个属性 useContext 这个确实用的挺少的 不过 还是简单做一下 打开我们的react项目 在src下创建一个文件夹 components 因为他是两个 甚至多个组件之间使用的 然后在components下创建两个组件 分别叫 dom.jsx dom1.jsx 命名命的比较不规范 不过本身只是做个案例 懒得做…

0-1背包

问题概述: 0-1背包是在n件物品取出若干件放在空间为V的背包里,每件物品的体积为v[ i ],与之相对应的价值为w[ i ],要求在不超过背包空间的情况下,得到的物品的价值总和最大,问这个最大值是多少? 问题分析…

pod 知识点 下

上一篇分享了 pod 的基本知识点,有 K8S 环境的小伙伴还是可以用起来的,还对比较简单,知道了 pod 的 yaml 文件结构,标识,基本的创建 pod 和删除 pod 的用法等等,我们继续 pod 的基本分类 前面我们说到了 p…

什么是Natural Language Generation(NLG)?

文章目录 1.NLG的定义2.NLP的步骤3.NLG生成文本方式有哪些?3.1.简单的数据合并3.2.模板化的NLG3.3.高级NLG 4.NLG的应用有哪些? 1.NLG的定义 自然语言生成(Natural Language Generation, NLG)是NLP(自然语言处理&…

Sikulix自动化工具的使用

1.Sikuli-x简介 Sikuli是识别和控制GUI组件进行UI自动化测试的技术,它是有MIT的研究人员开发进行设计的。Sikuli在墨西哥维乔印第安人(Huichol Indians)的语言里是上帝之眼的意思,Sikuli的工作模式与人眼一样,直接识别图像。 Sikuli-x是Sik…

1、Redis入门与安装配置

是什么? Remote Dictionary Server(远程字典服务) 是完全开源的,使用ANSIC语言编写遵守BSD协议,是一个高性能的Key-Value数据库。提供了丰富的数据结构,例如String、Hash、List、Set、SortedSet等等。数据是存在内存中的&#xf…

python爬虫-逆向实例小记-2

注意!!!!某数据网站逆向实例仅作为学习案例,禁止其他个人以及团体做谋利用途!!!! 案例分析 第一步:分析请求和响应内容。该网站任何一请求和内容都不可直接…

网站SEO优化的注意事项

SEO作为一种网络营销方式,高投入产出比是其优势所在。通过SEO优化为站点带来大量的主动搜索自然流量,对于企业主来说,是非常必要的。搜索引擎算法在不断发展,SEO技术也在不断发展。那么,如何能做好SEO呢?小…

投出去的简历无人问津,原因竟然在这……

近期收到了不少朋友的反馈说,失业半个月无人问津,放在前些年第二天开始面试有人找,或者是第二天入职了……,为啥明明不招人要挂着招人的岗位? 随着移动互联网的发展,Android市场的需求也在不断变化和升级。…

【springboot】—— 后端Springboot项目开发

后端Springboot项目开发 步骤1 先创建数据库,并在下面创建一个user表,插入数据,sql如下: CREATE TABLE user (id int(11) NOT NULL AUTO_INCREMENT COMMENT ID,email varchar(255) NOT NULL COMMENT 邮箱,password varchar(255)…

Turf.js:用于地理空间分析的 JavaScript 库

https://turfjs.org/ 处理和分析地理空间数据在许多应用程序和平台中发挥着至关重要的作用。如地图绘制、路径规划、基于位置的服务和地理空间分析。Turf.js 是一个专门为执行地理空间操作而开发的开源 JavaScript 库。在本文中,我将详细探讨 Turf.js ,…

Linux系统下列出库文件中的符号指令(nm)

文章目录 1 nm指令2 符号类型的含义3 简单示例 1 nm指令 nm是names的缩写, nm命令主要是用来列出某些文件中的符号(说白了就是一些函数和全局变量等)。 nm命令的输出包含三个部分: 1 符号值。默认显示十六进制,也可以…

SNMP 计算机网络管理 实验3(二)SNMP协议工作原理验证与分析

⬜⬜⬜ 🐰🟧🟨🟩🟦🟪(*^▽^*)欢迎光临 🟧🟨🟩🟦🟪🐰⬜⬜⬜ ✏️write in front✏️ 📝个人主页:陈丹宇jmu &am…

从零手写微前端qiankun框架【超详细万字长文】

项目创建 我们创建如图几个文件夹 main&#xff1a;主应用&#xff08;采用vue3作为技术栈&#xff09;react&#xff1a;子应用1vue2&#xff1a;子应用2vue3&#xff1a;子应用3service&#xff1a;服务端代码 vue2子应用&#xff1a; 我们在App.vue中写一点点东西 <t…

Java微服务金融项目智牛股-基础知识一(CAT链路监控)

CAT链路监控 背景&#xff1a;从单体架构到微服务架构的演变&#xff0c; 一个业务请求往往会流转多个服务&#xff0c; 大型互联网产品服务架构尤为复杂&#xff0c;腾讯的抢红包服务&#xff0c; 阿里的交易支付服务&#xff0c; 可能就流转成百上千个服务节点&#xff0c; 面…

HashMap夺命14问

1. HashMap的底层数据结构是什么&#xff1f; 在JDK1.7中和JDK1.8中有所区别&#xff1a; 在JDK1.7中&#xff0c;由”数组链表“组成&#xff0c;数组是HashMap的主体&#xff0c;链表则是主要为了解决哈希冲突而存在的。 在JDK1.8中&#xff0c;有“数组链表红黑树”组成。当…

【软考网络管理员】2023年软考网管初级常见知识考点(19)-防火墙与入侵检测系统IDS

涉及知识点 防火墙有哪些及其功能&#xff0c;防火墙的区域划分及工作模式&#xff0c;IDS是什么及其作用&#xff1f;入侵检测系统的分类及原理&#xff0c;软考网络管理员常考知识点&#xff0c;软考网络管理员网络安全&#xff0c;网络管理员考点汇总。 原创于&#xff1a;…

java.sql.Time 字段时区问题 Jackson 源码分析 意想不到的Time处理类

java.sql.Time 字段时区问题 系列文章目录 第一章 初步分析 第二章 Mybatis 源码分析 第三章 Jackson 源码分析 意想不到的Time处理类 文章目录 java.sql.Time 字段时区问题 系列文章目录前言Jackson 源码阅读1. 先找 JsonFormat.class 打断点一步步跟踪2. 跟踪进入实际处理类…

RTSP视频流相关的一些操作

播放rtsp camera 内容 端口554在网络通信中用于Real Time Streaming Protocol(RTSP)。 gst-launch-1.0 playbin urirtsp://admin:WANGfengtu1210.0.20.190:554/client0x gst-launch-1.0 playbin urirtsp://admin:WANGfengtu1210.0.20.61:554/client1xgst-launch-1.0 rtspsrc …

基于Arduino UNO的循迹小车

目录 1.analogWrite函数的使用 2.红外循迹模块介绍 3.循迹小车代码实现 4.实物示例 1.analogWrite函数的使用 用analogWrite来替换digitalWrite 说明 将一个模拟数值写进Arduino引脚。这个操作可以用来控制LED的亮度, 或者控制电机的转速. 在Arduino UNO控制器中&#…