航天基地规划建设局网站建设集团网站公司
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 | 
select live_id,max(sum) max_user_count
from (select *,sum(user_change) over (partition bylive_idorder bytime1) sumfrom (select user_id,live_id,in_datetime time1,1           user_changefrom live_eventsunion allselect user_id,live_id,out_datetime time1,-1           user_changefrom 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 | 
select user_id,page_id,view_timestamp,concat(user_id,'-',sum(flag) over (partition byuser_idorder byview_timestamp)) session_id
from (select *,`if`(view_timestamp - lag < 60, 0, 1) flagfrom (select *,lag(view_timestamp, 1, 0) over (partition byuser_idorder byview_timestamp) lagfrom 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 | 
select user_id,max(datediff) max_day_count
from (select user_id,sum,datediff(max(login_date), min(login_date)) + 1 datedifffrom (select *,sum(flag) over (partition byuser_idorder bylogin_date) sumfrom (select *,`if`(datediff(login_date, laglogin_date) > 2, 1, 0) flagfrom (select *,lag(login_date, 1, '1970-01-01') over (partition byuser_idorder bylogin_date) laglogin_datefrom (select user_id,date_format(login_datetime, 'yyyy-MM-dd') login_datefrom login_eventsgroup by user_id,date_format(login_datetime, 'yyyy-MM-dd')) t1) t2) t3) t4group 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 | 
select brand,sum(day_count) promotion_day_count
from (select *,casewhen start_date > maxend_date then datediff(end_date, start_date) + 1when end_date > maxend_date then datediff(end_date, maxend_date)else 0end day_countfrom (select *,nvl(max(end_date) over (partition bybrandorder bystart_date rows between unbounded precedingand 1 preceding),'1970-01-01') maxend_datefrom 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 | 
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_countfrom (select *,max(order_date) over () max_order_datefrom order_detail) t1where 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 | 
select t3.course_id,cast(user_count / size(ca.user_id) as decimal(16, 2)) adr
from (select course_id,count(1) user_countfrom (select course_id,user_id,sum(time1) sum_timefrom (select user_id, course_id, unix_timestamp(login_out) - unix_timestamp(login_in) time1from user_login) t1group by course_id, user_id) t2where sum_time > 40 * 60group by course_id) t3join course_apply caon 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 | 
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,casewhen 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                    periodfrom get_car_record gcrleft join get_car_order gcoon gcr.order_id = gco.order_idwhere `dayofweek`(event_time) between 2 and 6) t1
group by period; 
48、排列问题
现有球队表(team)如下。
| team_name (球队名称)  | 
|---|
| 湖人 | 
| 骑士 | 
| 灰熊 | 
| 勇士 | 
拿到所有球队比赛的组合 每个队只比一次
期望结果如下:
| team_name_1 <string> (队名)  | team_name_2 <string> (队名)  | 
|---|---|
| 勇士 | 湖人 | 
| 湖人 | 骑士 | 
| 灰熊 | 骑士 | 
| 勇士 | 骑士 | 
| 湖人 | 灰熊 | 
| 勇士 | 灰熊 | 
select t1.team_name team_name_1, t2.team_name team_name_2
from team t1join 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 | 
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)    zjfrom (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) wanbofrom user_video_log uvljoin video_info vion uvl.video_id = vi.video_id) t1group 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 | 
with t1 as (select id,en_dt,nvl(le_dt, '2020-03-31') le_dt,month(en_dt) + pos       monfrom emplateral 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_datefrom calgroup 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) zaifrom t1join t2on t1.mon = t2.mon) t3
group by mon; 
