高频HIVE-SQL笔试题详解

运维 数据库运维
在上期的SQL题目中,我们以求连续活跃为例,讲述了lead 、lag错位相减的用法。但若不采用错位相减的话,其实也可以实现这一目的。本次我们就先讲述一下最大连续活跃天数的第二种解法,然后再讲述另一常见面试SQL题目。

[[396437]]

本文转载自微信公众号「数师兄」,作者数师兄。转载本文请联系数师兄公众号。

在上期的SQL题目中,我们以求连续活跃为例,讲述了lead 、lag错位相减的用法。但若不采用错位相减的话,其实也可以实现这一目的。本次我们就先讲述一下最大连续活跃天数的第二种解法,然后再讲述另一常见面试SQL题目。

这一方法就是利用row_number给每一行生成一个连续的序号,这样,在连续活跃的时间段,就有了一个对照值,利用日期和行号这两者就可以得到一个差值,在连续活跃的时段内,其差值是相同的,那么我们按照这个差值进行分组就可以进一步计算本次连续活跃有多少天了。

SQL如下

  1. WITH active AS 
  2.   (SELECT 100 UID, 
  3.               '2021-04-01'dt 
  4.    UNION ALL SELECT 101 UID, 
  5.                         '2021-04-01'dt 
  6.    UNION ALL SELECT 102 UID, 
  7.                         '2021-04-01'dt 
  8.    UNION ALL SELECT 103 UID, 
  9.                         '2021-04-01'dt 
  10.    UNION ALL SELECT 100 UID, 
  11.                         '2021-04-02'dt 
  12.    UNION ALL SELECT 101 UID, 
  13.                         '2021-04-02'dt 
  14.    UNION ALL SELECT 102 UID, 
  15.                         '2021-04-02'dt 
  16.    UNION ALL SELECT 103 UID, 
  17.                         '2021-04-02'dt 
  18.    UNION ALL SELECT 104 UID, 
  19.                         '2021-04-02'dt 
  20.    UNION ALL SELECT 100 UID, 
  21.                         '2021-04-03'dt 
  22.    UNION ALL SELECT 104 UID, 
  23.                         '2021-04-03'dt 
  24.    UNION ALL SELECT 101 UID, 
  25.                         '2021-04-04'dt 
  26.    UNION ALL SELECT 102 UID, 
  27.                         '2021-04-04'dt 
  28.    UNION ALL SELECT 103 UID, 
  29.                         '2021-04-04'dt 
  30.    UNION ALL SELECT 104 UID, 
  31.                         '2021-04-04'dt 
  32.    UNION ALL SELECT 105 UID, 
  33.                         '2021-04-04'dt 
  34.    UNION ALL SELECT 102 UID, 
  35.                         '2021-04-03'dt) 
  36. SELECT UID, 
  37.        max(days)days 
  38. FROM 
  39.   (SELECT date_sub(dt,rn), 
  40.           UID, 
  41.           count(DISTINCT dt)days 
  42.    FROM 
  43.      (SELECT UID, 
  44.              dt, 
  45.              row_number()over(PARTITION BY UID 
  46.                               ORDER BY dt)rn 
  47.       FROM active)x 
  48.    GROUP BY date_sub(dt,rn), 
  49.             UID)y 
  50. GROUP BY UID 

结果如下:

至此,连续活跃的问题就告一段落了。下面我们来看另一个常见问题:

2.行列转换

(1)某直播产品,直播记录表lives中有liveid(直播id)、invite_list(邀约名单,string,用户id以“,”分割)字段,直播观看记录表record中有uid(用户id)、liveid(直播id)、duration(观看时长),试求出邀约名单中所有用户的观看时长

由于存在邀约用户未进房观看的问题,所以我们直接从观看记录中来取,不一定能将名单中所有用户包含进去,所以,我们需要以直播记录中的邀约名单为准。这就需要利用explode和lateral view来将这个string类型转换为行记录的形式。

仍然是使用with构造lives和record两个简单的临时表,详细SQL如下:

  1. with lives as
  2. select 100 liveid,'A01,A02,A03,A04'invite_list union all 
  3. select 101 liveid,'A05,A06,A07,A08'invite_list  
  4. ), 
  5. record as
  6. select 100 liveid,'A01' uid,30 duration union all 
  7. select 100 liveid,'A02' uid,50 duration union all 
  8. select 100 liveid,'A03' uid,15 duration union all 
  9. select 101 liveid,'A07' uid,20 duration union all 
  10. select 101 liveid,'A08' uid,60 duration 
  11.  
  12. select 
  13. list.liveid,list.ulist,if(record.duration is null,0,record.duration)duration 
  14. from ( 
  15. select liveid,ulist 
  16. from lives  
  17. lateral view explode(split(invite_list,',')) uid as ulist 
  18. )list left join record on list.liveid=record.liveid and list.ulist=record.uid 

这里简单说明下:lateral view 是为原表调用explode函数,将一个array或者map的字段分解成多行并作为一个临时表,然后再与其他字段组合到一起。

(2)某APP用户访问页面记录record,含有字段uid(用户id)、pageid(页面id),将每个用户的访问路径输出在一个字段中

前一道题目是列转行,这道题是行专列。利用collect_set可以将分组下面某个字段的所有记录聚合成一个列表,然后可以进一步使用concat_ws函数把array转为字符串,并用“>”将其连接起来。

  1. WITH record as 
  2.   (SELECT 100 UID,'A01' pageid 
  3.    UNION ALL SELECT 100 UID,'A02' pageid 
  4.    UNION ALL SELECT 100 UID,'A03' pageid 
  5.    UNION ALL SELECT 101 UID,'A07' pageid 
  6.    UNION ALL SELECT 101 UID,'A08' pageid) 
  7.     
  8.     
  9. SELECT UID, 
  10.        concat_ws('>',collect_list(pageid))page 
  11. FROM record 
  12. GROUP BY UID 

3.求留存

对于多数互联网公司来说,任何时候留存率都是重中之重。所以在数据分析的面试当中,求留存率的SQL题目出现的频率也是极高。

所谓“留存率”,通常是定义一个初始行为与一个后继行为,符合初始条件的用户量在经过N天之后,剩余的比例就是留存率。发散来讲,回访、复看等概念也与留存相类似。如:

某APP新注册用户表user,含有字段uid(用户id)、dt(注册日期),活跃表active,有字段uid(用户id),dt(活跃日期),求每天新增用户的次日留存率、次2日留存率、次3日留存率……次7日留存率

此题目就是以新注册作为初始行为,活跃作为后继行为。显而易见地,我们可以将初始行为与后继行为做左连接,然后按注册日期进行聚合,求相应的新增用户和次N日留存人数。

  1. WITH user as 
  2.   (SELECT 100 UID,'2021-01-01' dt 
  3.    UNION ALL SELECT 101 UID,'2021-01-01' dt 
  4.    UNION ALL SELECT 102 UID,'2021-01-01' dt 
  5.    UNION ALL SELECT 103 UID,'2021-01-02' dt 
  6.    UNION ALL SELECT 104 UID,'2021-01-02' dt 
  7.    UNION ALL SELECT 105 UID,'2021-01-02' dt 
  8.    UNION ALL SELECT 106 UID,'2021-01-02' dt), 
  9.    active as
  10.    select 100 UID,'2021-01-01'dt union all 
  11.    select 100 UID,'2021-01-02'dt union all 
  12.    select 100 UID,'2021-01-03'dt union all 
  13.    select 100 UID,'2021-01-05'dt union all 
  14.    select 100 UID,'2021-01-07'dt union all 
  15.    select 101 UID,'2021-01-01'dt union all 
  16.    select 101 UID,'2021-01-07'dt union all 
  17.    select 102 UID,'2021-01-01'dt union all 
  18.    select 103 UID,'2021-01-01'dt union all 
  19.    select 103 UID,'2021-01-02'dt union all 
  20.    select 103 UID,'2021-01-03'dt union all 
  21.    select 103 UID,'2021-01-05'dt union all 
  22.    select 104 UID,'2021-01-02'dt union all 
  23.    select 104 UID,'2021-01-03'dt union all 
  24.    select 104 UID,'2021-01-04'dt union all 
  25.    select 105 UID,'2021-01-02'dt union all 
  26.    select 105 UID,'2021-01-03'dt union all 
  27.    select 105 UID,'2021-01-04'dt union all 
  28.    select 105 UID,'2021-01-05'dt union all 
  29.    select 105 UID,'2021-01-07'dt union all 
  30.    select 106 UID,'2021-01-02'dt union all 
  31.    select 106 UID,'2021-01-04'dt  
  32.    ) 
  33.  
  34. select 
  35. user.dt, 
  36. count(distinct user.uid)new_user, 
  37. count(distinct if(datediff(active.dt,user.dt)=1,active.uid,null))retain1, 
  38. count(distinct if(datediff(active.dt,user.dt)=2,active.uid,null))retain2, 
  39. count(distinct if(datediff(active.dt,user.dt)=3,active.uid,null))retain3, 
  40. count(distinct if(datediff(active.dt,user.dt)=4,active.uid,null))retain4, 
  41. count(distinct if(datediff(active.dt,user.dt)=5,active.uid,null))retain5, 
  42. count(distinct if(datediff(active.dt,user.dt)=6,active.uid,null))retain6, 
  43. count(distinct if(datediff(active.dt,user.dt)=7,active.uid,null))retain7 
  44. from user left join active on user.uid=active.uid 
  45. group by user.dt 

其结果如下:

 

这种方法可能比较麻烦一些,得把要求的每一个留存指标都要单独写一个字段。若想省事儿,可以单独求出每日的新增数量,再将新增表与活跃表连接而求出每个注册日期在后续每天的活跃数量,然后将新增数量与活跃数量再进行关联,从而求得任意周期的留存。

 

责任编辑:武晓燕 来源: 数师兄
相关推荐

2021-04-21 08:11:09

HIVE-SQLSQL数据库

2009-08-01 22:47:13

ASP.NET笔试题目ASP.NET

2021-12-08 11:18:21

Spring Bean面试题生命周期

2021-02-23 12:43:39

Redis面试题缓存

2009-06-15 17:18:25

Java笔试题

2015-04-07 14:05:13

前端阿里在线笔试题

2010-08-18 10:17:00

2010-08-16 15:27:22

雅虎笔试题

2020-06-01 08:39:12

JavaScript开发技术

2010-08-11 11:57:02

微软笔试题微软笔试题

2010-08-11 11:32:57

谷歌笔试题谷歌笔试题

2010-08-11 11:22:00

IBM笔试题IBM笔试

2010-08-11 12:07:08

腾讯笔试题腾讯笔试题

2009-07-28 13:35:18

2021-01-22 11:58:30

MySQL数据库开发

2009-07-28 13:09:51

ASP.NET笔试题

2009-02-27 10:46:32

DBA笔试题阿里巴巴

2009-07-14 10:05:02

HCDA认证考试笔试题

2011-08-11 17:39:25

Objective-C笔试题

2010-08-18 10:27:56

点赞
收藏

51CTO技术栈公众号