当前位置:   article > 正文

HiveSQL题——前后函数(lag/lead)_hive sql lag

hive sql lag

目录

一、窗口函数的知识点

1.1 窗户函数的定义

1.2 窗户函数的语法

1.3 窗口函数分类

1.4 前后函数:lag/lead

二、实际案例

2.1 股票的波峰波谷

0 问题描述

1 数据准备

2 数据分析

3 小结

2.2 前后列转换(面试题)

0 问题描述

1 数据准备

2 数据分析

3 小结

一、窗口函数的知识点

1.1 窗户函数的定义

         窗口函数可以拆分为【窗口+函数】。窗口函数官网指路:LanguageManual WindowingAndAnalytics - Apache Hive - Apache Software Foundationicon-default.png?t=N7T8https://cwiki.apache.org/confluence/display/Hive/LanguageManual+WindowingAndAnalytics

  • 窗口定义函数计算范围(窗口函数:针对分组后的数据,从逻辑角度指定计算的范围,并没有从物理上真正的切分,只有group by 是物理分组,真正意义上的分组)
  • 函数定义函数计算逻辑
  • sql 执行顺序
  1. from ->
  2. join ->
  3. on ->
  4. where ->
  5. group by->
  6. with (可以在分组后面加上 with rollup,在分组之后对每个组进行全局汇总) ->
  7. select 后面的普通字段,聚合函数->
  8. having(having中可以使用select 字段别名) ->
  9. distinct ->
  10. order by ->
  11. limit
  • 窗口函数执行顺序窗口函数是作用于select后的结果集。select 的结果集作为窗口函数的输入,但是位于 distcint 之前。窗口函数的执行结果只是在原有的列中单独添加一列,形成新的列,它不会对已有的行或列做修改。

1.2 窗户函数的语法

       <窗口函数>window_name  over ( [partition by 字段...]  [order by 字段...]  [窗口子句] )

  • window_name:给窗口指定一个别名。
  • over:用来指定函数执行的窗口范围,如果后面括号中什么都不写,即over() ,意味着窗口包含满足where 条件的所有行,窗口函数基于所有行进行计算。
  • 符号[] 代表:可选项;  | : 代表二选一
  •  partition by 子句: 窗口按照哪些字段进行分组,窗口函数在不同的分组上分别执行。分组间互相独立。
  • order by 子句  :每个partition内部按照哪些字段进行排序,如果没有partition ,那就直接按照最大的窗口排序,且默认是按照升序(asc)排列。
  • 窗口子句:显示声明范围(不写窗口子句的话,会有默认值)。常用的窗口子句如下:
  1. rows between unbounded preceding and unbounded following; -- 上无边界到下无边界(一般用于求 总和)
  2. rows between unbounded preceding and current row; --上无边界到当前记录(累计值)
  3. rows between 1 preceding and current row; --从上一行到当前行
  4. rows between 1 preceding and 1 following; --从上一行到下一行
  5. rows between current row and 1 following; --从当前行到下一行

     ps: over()里面有order by子句,但没有窗口子句时 ,即: <窗口函数> over ( partition by 字段... order by 字段... ),此时窗口子句是有默认值的->  rows between unbounded preceding and current row (上无边界到当前行)

      此时窗口函数语法:<窗口函数> over ( partition by 字段... order by 字段... ) 等价于

     <窗口函数> over ( partition by 字段... order by 字段... rows between unbounded preceding and current row)
     需要注意有个特殊情况:当order by 后面跟的某个字段是有重复行的时候, <窗口函数> over ( partition by 字段... order by 字段... )  不写窗口子句的情况下,窗口子句的默认值是:range between unbounded preceding and current row(上无边界到当前相同行的最后一行)

    因此,遇到order by 后面跟的某个字段出现重复行,且需要计算【上无边界到当前行】,那就需要手动指定 窗口子句 rows between unbounded preceding and current row ,偷懒省略窗口子句会出问题~

    总结如下:

  1. 1、窗口子句不能单独出现,必须有order by子句时才能出现。
  2. 2、当省略窗口子句时:
  3. a) 如果存在order by则默认的窗口是unbounded preceding and current row --当前组的第一行到当前行,即在当前组中,第一行到当前行
  4. b) 如果没有order by则默认的窗口是unbounded preceding and unbounded following --整个组

      ps: 窗口函数的执行顺序是在where之后,所以如果where子句需要用窗口函数作为条件,需要多一层查询,在子查询外面进行。

     【例如】求出登录记录出现间断的用户Id

  1. select
  2. id
  3. from (
  4. select
  5. id,
  6. login_date,
  7. lead(login_date, 1, '9999-12-31')
  8. over (partition by id order by login_date) next_login_date
  9. --窗口函数 lead(向后取n行)
  10. --lead(column1,n,default)over(partition by column2 order by column3) 查询当前行的后边第n行数据,如果没有就为null
  11. from (--用户在同一天可能登录多次,需要去重
  12. select
  13. id,
  14. date_format(`date`, 'yyyy-MM-dd') as login_date
  15. from user_log
  16. group by id, date_format(`date`, 'yyyy-MM-dd')
  17. ) tmp1
  18. ) tmp2
  19. where datediff(next_login_date, login_date) >=2
  20. group by id;
  • 窗口函数本身也有执行顺序: <窗口函数>over ( partition by  order by   窗口子句 )的执行顺序:over -> partition by -> order by -> 窗口子句 -> 函数

1.3 窗口函数分类

      哪些函数可以是窗口函数呢?(放在over关键字前面的)

  • 聚合函数

  1. sum(column) over (partition by .. order by .. 窗口子句);
  2. count(column) over (partition by .. order by .. 窗口子句);
  3. max(column) over (partition by .. order by .. 窗口子句);
  4. min(column) over (partition by .. order by .. 窗口子句);
  5. avg(column) over (partition by .. order by .. 窗口子句);

  需要注意:

  1. 1.count(*)操作时会统计null值,count(column)会过滤掉null值;
  2. 2.事实上除了count(*)计算,剩余的聚合函数例如: max(column),min(column),avg(column),count(column) 函数会过滤掉null

 ps : 高级聚合函数

         collect_list 收集并形成list集合,结果不去重;

         collect_set 收集并形成set集合,结果去重; 

      举例:

  1. --每个月的入职人数以及姓名
  2. select
  3. month(replace(hiredate,'/','-')),
  4. count(*) as cnt,
  5. collect_list(name) as name_list
  6. from employee
  7. group by month(replace(hiredate,'/','-'));
  8. /*
  9. 输出结果
  10. month cn name_list
  11. 4 2 ["宋青书","周芷若"]
  12. 6 1 ["黄蓉"]
  13. 7 1 ["郭靖"]
  14. 8 2 ["张无忌","杨过"]
  15. 9 2 ["赵敏","小龙女"]
  16. */
  • 排序函数

      rank() 、row_number() 、dense_rank() 函数不支持自定义窗口子句。

  1. -- 顺序排序——1、2、3
  2. row_number() over(partition by .. order by .. )
  3. -- 并列排序,跳过重复序号——1、1、3(横向加)
  4. rank() over(partition by .. order by .. )
  5. -- 并列排序,不跳过重复序号——1、1、2(纵向加)
  6. dense_rank() over(partition by .. order by .. )
  • 前后函数 

  1. -- 取得column列前边的第n行数据,如果存在则返回,如果不存在,返回默认值default
  2. lag(column,n,default) over(partition by order by) as lag_test
  3. -- 取得column列后边的第n行数据,如果存在则返回,如果不存在,返回默认值default
  4. lead(column,n,default) over(partition by order by) as lead_test
  • 头尾函数

  1. ---当前窗口column列的第一个数值,如果有null值,则跳过
  2. first_value(column,true) over (partition by ..order by.. 窗口子句)
  3. ---当前窗口column列的第一个数值,如果有null值,不跳过
  4. first_value(column,false) over (partition by ..order by.. 窗口子句)
  5. --- 当前窗口column列的最后一个数值,如果有null值,则跳过
  6. last_value(column,true) over (partition by ..order by.. 窗口子句)
  7. --- 当前窗口column列的最后一个数值,如果有null值,不跳过
  8. last_value(column,false) over (partition by ..order by.. 窗口子句)

1.4 前后函数:lag/lead

       lead和lag函数,这两个函数一般用于计算差值,上面已介绍其语法。laglead函数不支持自定义窗口子句。

  1. -- 取得column列前边的第n行数据,如果存在则返回,如果不存在,返回默认值default
  2. lag(column,n,default) over(partition by order by) as lag_test
  3. -- 取得column列后边的第n行数据,如果存在则返回,如果不存在,返回默认值default
  4. lead(column,n,default) over(partition by order by) as lead_test

二、实际案例

2.1 股票的波峰波谷

0 问题描述

    求股票的波峰Crest 和 波谷trough

  1. 波峰:当天的股票价格大于前一天和后一天
  2. 波谷:当天的股票价格小于前一天和后一天

1 数据准备

  1. create table if not exists table2
  2. (
  3. id int comment '股票id',
  4. dt string comment '日期',
  5. price int comment '价格'
  6. )
  7. comment '股票价格波动信息';
  8. insert overwrite table table2 values
  9. (1,'2019-01-01',10001),
  10. (1,'2019-01-03',1001),
  11. (1,'2019-01-02',1001),
  12. (1,'2019-01-04',1000),
  13. (1,'2019-01-05',1002),
  14. (1,'2019-01-06',1003),
  15. (1,'2019-01-07',1004),
  16. (1,'2019-01-08',998),
  17. (1,'2019-01-09',997),
  18. (2,'2019-01-01',1002),
  19. (2,'2019-01-02',1003),
  20. (2,'2019-01-03',1004),
  21. (2,'2019-01-04',998),
  22. (2,'2019-01-05',999),
  23. (2,'2019-01-06',997),
  24. (2,'2019-01-07',996);

2 数据分析

  此题容易理解,利用lag()和lead()函数便可以解决。

  1. select
  2. id,
  3. dt,
  4. price,
  5. case
  6. when price > lag_price and price > lead_price then 'crest'
  7. when price < lag_price and price < lead_price then 'trough'
  8. end as price_type
  9. from (
  10. select
  11. id,
  12. dt,
  13. price,
  14. lag(price, 1) over (partition by id order by dt) as lag_price,
  15. lead(price, 1) over (partition by id order by dt) as lead_price
  16. from table2
  17. ) tmp1;

3 小结

    lead和lag函数一般用于计算当前行与上一行,或者当前行与下一行之间的差值。在用户间断登陆问题中也遇到过此函数。指路:HiveSQL题——用户连续登陆-CSDN博客文章浏览阅读220次,点赞4次,收藏3次。HiveSQL题——用户连续登陆https://blog.csdn.net/SHWAITME/article/details/135900251?spm=1001.2014.3001.5501

2.2 前后列转换(面试题)

0 问题描述

    表temp包含A,B 两列,使用SQL对该B列进行处理,形成C列。按照A列顺序,B列值不变,C列累计技术 B列值变化,则C列重新开始计数,如图所示

   

1 数据准备

  1. with table4 as (
  2. select 2010 as A,1 as B
  3. union all
  4. select 2011 as A,1 as B
  5. union all
  6. select 2012 as A,1 as B
  7. union all
  8. select 2013 as A,0 as B
  9. union all
  10. select 2014 as A,0 as B
  11. union all
  12. select 2015 as A,1 as B
  13. union all
  14. select 2016 as A,1 as B
  15. union all
  16. select 2017 as A,1 as B
  17. union all
  18. select 2018 as A,0 as B
  19. union all
  20. select 2019 as A,0 as B
  21. )

2 数据分析

  1. with table4 as (
  2. select 2010 as A,1 as B
  3. union all
  4. select 2011 as A,1 as B
  5. union all
  6. select 2012 as A,1 as B
  7. union all
  8. select 2013 as A,0 as B
  9. union all
  10. select 2014 as A,0 as B
  11. union all
  12. select 2015 as A,1 as B
  13. union all
  14. select 2016 as A,1 as B
  15. union all
  16. select 2017 as A,1 as B
  17. union all
  18. select 2018 as A,0 as B
  19. union all
  20. select 2019 as A,0 as B
  21. )
  22. select
  23. A,
  24. B,
  25. row_number() over (partition by T order by A) as C
  26. from (
  27. select
  28. A,
  29. B,
  30. --over (order by A) 本质是 :over(order by rows between unbounded preceding and current row )
  31. --省略的是:上无边界到当前行
  32. sum(change) over (order by A) T
  33. from (
  34. select
  35. A,
  36. B,
  37. -- 向上取一行,取不到的记为0
  38. lag(B, 1, 0) over (order by A) as Lag,
  39. case
  40. when B <> lag(B, 1, 0) over (order by A) then 1
  41. else 0
  42. end as change
  43. from table4
  44. ) tmp1
  45. ) tmp2;

3 小结

    lead /lag函数常用于差值计算。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/649897
推荐阅读
相关标签
  

闽ICP备14008679号