HiveSQL刷题

41、同时在线人数问题

现有各直播间的用户访问记录表(live_events)如下,表中每行数据表达的信息为,一个用户何时进入了一个直播间,又在何时离开了该直播间。

user_id (用户id) live_id (直播间id) in_datetime (进入直播间的时间) out_datetime (离开直播间的时间)
100 1 2021-12-1 19:30:00 2021-12-1 19:53:00
100 2 2021-12-1 21:01:00 2021-12-1 22:00:00
101 1 2021-12-1 19:05:00 2021-12-1 20:55:00

现要求统计各直播间最大同时在线人数,期望结果如下:

live_id <int> (直播id) max_user_count <int> (最大人数)
1 4
2 3
3 2
sql 复制代码
select live_id,
       max(sum) max_user_count
from (select *,
             sum(user_change) over (
                 partition by
                     live_id
                 order by
                     time1
                 ) sum
      from (select user_id,
                   live_id,
                   in_datetime time1,
                   1           user_change
            from live_events
            union all
            select user_id,
                   live_id,
                   out_datetime time1,
                   -1           user_change
            from live_events) t1) t2
group by live_id;

42、会话划分问题

现有页面浏览记录表(page_view_events)如下,表中有每个用户的每次页面访问记录。

user_id page_id view_timestamp
100 home 1659950435
100 good_search 1659950446
100 good_list 1659950457
100 home 1659950541
100 good_detail 1659950552
100 cart 1659950563
101 home 1659950435
101 good_search 1659950446
101 good_list 1659950457
101 home 1659950541
101 good_detail 1659950552
101 cart 1659950563
102 home 1659950435
102 good_search 1659950446
102 good_list 1659950457
103 home 1659950541
103 good_detail 1659950552
103 cart 1659950563

规定若同一用户的相邻两次访问记录时间间隔小于60s,则认为两次浏览记录属于同一会话。现有如下需求,为属于同一会话的访问记录增加一个相同的会话id字段,会话id格式为"user_id-number",其中number从1开始,用于区分同一用户的不同会话,期望结果如下:

user_id <int> (用户id) page_id <string> (页面id) view_timestamp <bigint> (浏览时间戳) session_id <string> (会话id)
100 home 1659950435 100-1
100 good_search 1659950446 100-1
100 good_list 1659950457 100-1
100 home 1659950541 100-2
100 good_detail 1659950552 100-2
100 cart 1659950563 100-2
101 home 1659950435 101-1
101 good_search 1659950446 101-1
101 good_list 1659950457 101-1
101 home 1659950541 101-2
101 good_detail 1659950552 101-2
101 cart 1659950563 101-2
102 home 1659950435 102-1
102 good_search 1659950446 102-1
102 good_list 1659950457 102-1
103 home 1659950541 103-1
103 good_detail 1659950552 103-1
sql 复制代码
select user_id,
       page_id,
       view_timestamp,
       concat(
               user_id,
               '-',
               sum(flag) over (
                   partition by
                       user_id
                   order by
                       view_timestamp
                   )
           ) session_id
from (select *,
             `if`(view_timestamp - lag < 60, 0, 1) flag
      from (select *,
                   lag(view_timestamp, 1, 0) over (
                       partition by
                           user_id
                       order by
                           view_timestamp
                       ) lag
            from page_view_events) t1) t2;

43、间断连续登录用户问题

现有各用户的登录记录表(login_events)如下,表中每行数据表达的信息是一个用户何时登录了平台。

user_id login_datetime
100 2021-12-01 19:00:00
100 2021-12-01 19:30:00
100 2021-12-02 21:01:00

现要求统计各用户最长的连续登录天数,间断一天也算作连续,例如:一个用户在1,3,5,6登录,则视为连续6天登录。期望结果如下:

user_id <int> (用户id) max_day_count <int> (最大连续天数)
100 3
101 6
102 3
104 3
105 1
sql 复制代码
select user_id,
       max(datediff) max_day_count
from (select user_id,
             sum,
             datediff(max(login_date), min(login_date)) + 1 datediff
      from (select *,
                   sum(flag) over (
                       partition by
                           user_id
                       order by
                           login_date
                       ) sum
            from (select *,
                         `if`(datediff(login_date, laglogin_date) > 2, 1, 0) flag
                  from (select *,
                               lag(login_date, 1, '1970-01-01') over (
                                   partition by
                                       user_id
                                   order by
                                       login_date
                                   ) laglogin_date
                        from (select user_id,
                                     date_format(login_datetime, 'yyyy-MM-dd') login_date
                              from login_events
                              group by user_id,
                                       date_format(login_datetime, 'yyyy-MM-dd')) t1) t2) t3) t4
      group by user_id,
               sum) t5
group by user_id;

44、日期交叉问题

现有各品牌优惠周期表(promotion_info)如下,其记录了每个品牌的每个优惠活动的周期,其中同一品牌的不同优惠活动的周期可能会有交叉。

promotion_id brand start_date end_date
1 oppo 2021-06-05 2021-06-09
2 oppo 2021-06-11 2021-06-21
3 vivo 2021-06-05 2021-06-15

现要求统计每个品牌的优惠总天数,若某个品牌在同一天有多个优惠活动,则只按一天计算。期望结果如下:

brand <string> (品牌) promotion_day_count <int> (优惠天数)
vivo 17
oppo 16
redmi 22
huawei 22
sql 复制代码
select brand,
       sum(day_count) promotion_day_count
from (select *,
             case
                 when start_date > maxend_date then datediff(end_date, start_date) + 1
                 when end_date > maxend_date then datediff(end_date, maxend_date)
                 else 0
                 end day_count
      from (select *,
                   nvl(
                           max(end_date) over (
                               partition by
                                   brand
                               order by
                                   start_date rows between unbounded preceding
                                   and 1 preceding
                               ),
                           '1970-01-01'
                       ) maxend_date
            from promotion_info) t1) t2
group by brand;

45、复购率问题

现有电商订单表(order_detail)如下。

order_id (订单id) user_id (用户id) product_id (商品id) price (售价) cnt (数量) order_date (下单时间)
1 1 1 5000 1 2022-01-01
2 1 3 5500 1 2022-01-02
3 1 7 35 2 2022-02-01
4 2 2 3800 3 2022-03-03

注:复购率指用户在一段时间内对某商品的重复购买比例,复购率越大,则反映出消费者对品牌的忠诚度就越高,也叫回头率

此处我们定义:某商品复购率 = 近90天内购买它至少两次的人数 ÷ 购买它的总人数

近90天指包含最大日期(以订单详情表(order_detail)中最后的日期)在内的近90天。结果中复购率保留2位小数,并按复购率倒序、商品ID升序排序。

期望结果如下:

product_id <int> (商品id) crp <decimal(16,2)> (复购率)
3 1.00
9 1.00
8 0.50
5 0.33
7 0.25
1 0.00
2 0.00
6 0.00
sql 复制代码
select product_id,
       cast(count(`if`(user_count >= 2, 1, null)) / count(1) as decimal(16, 2)) cpr
from (select product_id,
             user_id,
             count(1) user_count
      from (select *,
                   max(order_date) over () max_order_date
            from order_detail) t1
      where order_date >= date_sub(max_order_date, 90)
      group by product_id, user_id) t2
group by product_id
order by cpr desc, product_id;

46、出勤率问题

现有用户出勤表(user_login)如下。

user_id (用户id) course_id (课程id) login_in (登录时间) login_out (登出时间)
1 1 2022-06-02 09:08:24 2022-06-02 10:09:36
1 1 2022-06-02 11:07:24 2022-06-02 11:44:21
1 2 2022-06-02 13:50:24 2022-06-02 14:21:50
2 2 2022-06-02 13:50:10 2022-06-02 15:30:20

课程报名表(course_apply)如下。

course_id (课程id) course_name (课程名称) user_id (用户id)
1 java [1,2,3,4,5,6]
2 大数据 [1,2,3,6]
3 前端 [2,3,4,5]

注:出勤率指用户看直播时间超过40分钟,求出每个课程的出勤率(结果保留两位小数)。

期望结果如下:

course_id <int> (课程id) adr <decimal(16,2)> (出勤率)
1 0.33
2 0.50
3 0.25
sql 复制代码
select t3.course_id,
       cast(user_count / size(ca.user_id) as decimal(16, 2)) adr
from (select course_id,
             count(1) user_count
      from (select course_id,
                   user_id,
                   sum(time1) sum_time
            from (select user_id, course_id, unix_timestamp(login_out) - unix_timestamp(login_in) time1
                  from user_login) t1
            group by course_id, user_id) t2
      where sum_time > 40 * 60
      group by course_id) t3
         join course_apply ca
              on ca.course_id = t3.course_id;

47、打车问题

现有用户下单表(get_car_record)如下。

uid (用户id) city (城市) event_time (下单时间) end_time (结束时间:取消或者接单) order_id (订单id)
107 北京 2021-09-20 11:00:00 2021-09-20 11:00:30 9017
108 北京 2021-09-20 21:00:00 2021-09-20 21:00:40 9008
108 北京 2021-09-20 18:59:30 2021-09-20 19:01:00 9018
102 北京 2021-09-21 08:59:00 2021-09-21 09:01:00 9002

司机订单信息表(get_car_order)如下。

order_id (课程id) uid (用户id) driver_id (用户id) order_time (接单时间) start_time (开始时间) finish_time (结束时间) fare (费用) grade (评分)
9017 107 213 2021-09-20 11:00:30 2021-09-20 11:02:10 2021-09-20 11:31:00 38 5
9008 108 204 2021-09-20 21:00:40 2021-09-20 21:03:00 2021-09-20 21:31:00 38 4
9018 108 214 2021-09-20 19:01:00 2021-09-20 19:04:50 2021-09-20 19:21:00 38 5

统计周一到周五各时段的叫车量、平均等待接单时间和平均调度时间。全部以event_time-开始打车时间为时段划分依据,平均等待接单时间和平均调度时间均保留2位小数,平均调度时间仅计算完成了的订单,结果按叫车量升序排序。

注:不同时段定义:早高峰 [07:00:00 , 09:00:00)、工作时间 [09:00:00 , 17:00:00)、晚高峰 [17:00:00 ,20:00:00)、休息时间 [20:00:00 , 07:00:00) 时间区间左闭右开(即7:00:00算作早高峰,而9:00:00不算做早高峰)

从开始打车到司机接单为等待接单时间,从司机接单到上车为调度时间

期望结果如下:

period <string> (时段) get_car_num <int> (叫车量) wait_time <decimal(16,2)> (等待时长) dispatch_time <decimal(16,2)> (调度时长)
工作时间 1 0.50 1.67
休息时间 1 0.67 2.33
晚高峰 3 2.06 7.28
早高峰 4 2.21 8.00
sql 复制代码
select period,
       count(1)                                                  get_car_num,
       cast(avg(end_time - event_time) / 60 as decimal(16, 2))   wait_time,
       cast(avg(start_time - order_time) / 60 as decimal(16, 2)) dispatch_time
from (select unix_timestamp(event_time) event_time,
             unix_timestamp(end_time)   end_time,
             unix_timestamp(order_time) order_time,
             unix_timestamp(start_time) start_time,
             case
                 when hour(event_time) between 7 and 8 then '早高峰'
                 when hour(event_time) between 9 and 16 then '工作时间'
                 when hour(event_time) between 17 and 19 then '晚高峰'
                 else '休息时间'
                 end                    period
      from get_car_record gcr
               left join get_car_order gco
                         on gcr.order_id = gco.order_id
      where `dayofweek`(event_time) between 2 and 6) t1
group by period;

48、排列问题

现有球队表(team)如下。

team_name (球队名称)
湖人
骑士
灰熊
勇士

拿到所有球队比赛的组合 每个队只比一次

期望结果如下:

team_name_1 <string> (队名) team_name_2 <string> (队名)
勇士 湖人
湖人 骑士
灰熊 骑士
勇士 骑士
湖人 灰熊
勇士 灰熊
sql 复制代码
select t1.team_name team_name_1, t2.team_name team_name_2
from team t1
         join team t2
where t1.team_name < t2.team_name;

49、视频热度问题

现有用户视频表(user_video_log)如下。

uid (球队名称) video_id (视频id) start_time (开始时间) end_time (结束时间) if_like (是否点赞) if_retweet (是否喜欢) comment_id (评论id)
101 2001 2021-09-24 10:00:00 2021-09-24 10:00:20 1 0 null
105 2002 2021-09-25 11:00:00 2021-09-25 11:00:30 0 1 null
102 2002 2021-09-25 11:00:00 2021-09-25 11:00:30 1 1 null
101 2002 2021-09-26 11:00:00 2021-09-26 11:00:30 0 1 null

视频信息表(video_info) 如下:

video_id (视频id) author (作者id) tag (标签) duration (视频时长)
2001 901 旅游 30
2002 901 旅游 60
2003 902 影视 90
2004 902 美女 90

找出近一个月发布的视频中热度最高的top3视频。

注:热度=(a*视频完播率+b*点赞数+c*评论数+d*转发数)*新鲜度;

新鲜度=1/(最近无播放天数+1);

当前配置的参数a,b,c,d分别为100、5、3、2。

最近播放日期以 end_time-结束观看时间 为准,假设为T,则最近一个月按 [T-29, T] 闭区间统计。

当天日期使用视频中最大的end_time

结果中热度保留为整数,并按热度降序排序。

期望结果如下:

video_id <int> (视频id) heat <decimal(16,2)> (热度)
2002 80.36
2001 20.33
sql 复制代码
select video_id,
       cast(ceil((100 * wb + 5 * dz + 3 * pl + 2 * zf) * 1) as decimal(16, 1)) heat
from (select video_id,
             sum(wanbo) / count(1) wb,
             sum(if_like)          dz,
             count(comment_id)     pl,
             sum(if_retweet)       zf,
             min(datediff_time)    zj
      from (select uvl.video_id,
                   if_like,
                   comment_id,
                   if_retweet,
                   datediff(max(end_time) over (), end_time)                                     datediff_time,
                   `if`(unix_timestamp(end_time) - unix_timestamp(start_time) >= duration, 1, 0) wanbo
            from user_video_log uvl
                     join video_info vi
                          on uvl.video_id = vi.video_id) t1
      group by video_id) t2;

50、员工在职人数问题

现有用户表(emp)如下。

id (员工id) en_dt (入职日期) start_time (离职日期)
1001 2020-01-02 null
1002 2020-01-02 2020-03-05
1003 2020-02-02 2020-02-15
1004 2020-02-12 2020-03-08

日历表(cal) 如下:

dt (日期)
2020-01-01
2020-01-02
2020-01-03
2020-01-04

统计2020年每个月实际在职员工数量(只统计2020-03-31之前),如果1个月在职天数只有1天,数量计算方式:1/当月天数。

如果一个月只有一天的话,只算30分之1个人

期望结果如下:

mnt <int> (月份) ps <decimal(16,2)> (在职人数)
1 1.94
2 3.62
3 2.23
sql 复制代码
with t1 as (select id,
                   en_dt,
                   nvl(le_dt, '2020-03-31') le_dt,
                   month(en_dt) + pos       mon
            from emp
                     lateral view posexplode(split(repeat('a', month(nvl(le_dt, '2020-03-31')) - month(en_dt)),
                                                   'a')) tbl as pos, val),
     t2 as (select month(dt) mon,
                   max(dt)   max_date,
                   min(dt)   min_date
            from cal
            group by month(dt))
select mon                              mth,
       cast(sum(zai) as decimal(16, 2)) ps
from (select t1.mon,
             (datediff(`if`(le_dt > max_date, max_date, le_dt), `if`(en_dt > min_date, en_dt, min_date)) + 1) /
             (datediff(max_date, min_date) + 1) zai
      from t1
               join t2
                    on t1.mon = t2.mon) t3
group by mon;
相关推荐
@月落11 分钟前
alibaba获得店铺的所有商品 API接口
java·大数据·数据库·人工智能·学习
天地风雷水火山泽16 分钟前
二百六十六、Hive——Hive的DWD层数据清洗、清洗记录、数据修复、数据补全
数据仓库·hive·hadoop
码爸1 小时前
spark读mongodb
大数据·mongodb·spark
WPG大大通1 小时前
有奖直播 | onsemi IPM 助力汽车电气革命及电子化时代冷热管理
大数据·人工智能·汽车·方案·电气·大大通·研讨会
ws2019071 小时前
抓机遇,促发展——2025第十二届广州国际汽车零部件加工技术及汽车模具展览会
大数据·人工智能·汽车
Data-Miner2 小时前
196页满分PPT | 集团流程优化及IT规划项目案例
大数据·数据分析
徐*红2 小时前
Elasticsearch 8.+ 版本查询方式
大数据·elasticsearch
大数据深度洞察2 小时前
Hive企业级调优[2]—— 测试用表
数据仓库·hive·hadoop
DolphinScheduler社区2 小时前
怎么办?用DolphinScheduler调度执行复杂的HiveSQL时无法正确识别符号
大数据
lzhlizihang2 小时前
使用sqoop将mysql数据导入到hive报错ClassNotFoundException、Zero date value prohibited等错误
hive·报错·sqoop