更多数据分析思维、工具、实际项目和面试面经文章请查看共粽号:【数据分析星球】。
01、写在前面
无论你是刚毕业的职场小鲜肉、还是想转行数据分析的小白玩家,只要想进入数据分析的行业,都逃不过数据分析面试的考验,这里最重要也是最关键的一关就是SQL笔试了,不过不用担心,结合作者6年+的工作和面试经验,系统全面地整理了数据分析面试中那些高频出现的以及各大厂的SQL笔试题,学习了这些笔试题的常见套路和解法,把这些题目都刷一遍,在接下来的笔试中应该可以一往无前,收割offer啦!
数据分析笔试中最常见也是最有难度的就是SQL窗口函数了,SQL窗口函数作为SQL的高阶语法,也是数分工作中最常用的分析函数,也是面试中最常考查的知识点,本文就讲解了各大厂考查的窗口函数题目,通过这些题目就能熟练掌握这个知识点了。
02、计算连续活跃/登录
连续活跃或者登录的计算是数据分析业务场景中非常经典和常见的问题,而且涉及到的解题思路比较巧妙,所以也是面试笔试中非常喜欢考查的知识点,通过下面的笔试题的详细讲解,希望小伙伴们可以举一反三,把计算连续这类问题吃透。
记录用户活跃时间信息的表user_active如下:
需求:计算连续活跃2天及以上的用户。
第1步:用户活跃日期去重
因为一个用户同一天可能活跃多次,我们只需要知道用户在某天是否活跃即可,所以需要对用户id+活跃日期去重。
select DISTINCT
cast(active_time as date) active_day,
userid
from user_active;
查询结果:
第2步:窗口函数按日期排序
有了第1步去重后的结果,我们可以用row_number() 函数对其进行开窗,以userid分组,日期升序排序,得到每个用户按照日期升序的排名。
select *,
row_number() over(PARTITION by userid
order by active_day) as rn
from
(
select DISTINCT
cast(active_time as date) active_day,
userid
from user_active;
)a;
查询结果:
看到这里,有些小伙伴可能就比较疑惑了,为什么要在这一步对日期进行排序呢?这也是计算连续活跃、达标逻辑比较tricky的地方,因为我们用row_number排序之后的名次是连续的,那么如果恰巧日期也是连续的,日期和排序差值不就是一个固定的值了吗?所有连续的日期是不是都被这个固定的值圈定了?
第3步:确定连续日期的分组
按照上面所说的逻辑,我们使用date_sub函数将当前日期active_day和当前的排序值rn相减,得到一个新的列,命名为"day_group"
select *,
date_sub(active_day,rn) as day_group
from
(
select *,
row_number()over(PARTITION by userid
order by active_day) as rn
from
(
select DISTINCT
cast(active_time as date)active_day,
userid
from user_active;
)a
)b;
查询结果:
第4步:根据分组列计算连续天数
最后一步,我们直接根据第3步中获取到的分组列,根据userid和分组列进行分组求count即可。如果是要求连续活跃2天以上,我们直接对聚合后的count 用having进行过滤即可。
select userid,day_group,
count(*) as continous_days
from
(
select *,
date_sub(active_day,rn) day_group
from
(
select *,
row_number()over(PARTITION by
userid order by active_day) as rn
from
(
select DISTINCT
cast(active_time as date)active_day,
userid
from user_active
)a
)b
)c
GROUP BY userid,day_group
having count(*)>=2;
查询结果:
到这里结果就出来了,userid为10001和10002的用户都连续活跃了3天,也就是符合我们条件的用户。
03、计算累计指标
求累计也是数据分析实际业务中非常常见的场景,截止到每天的累计销售额、截止到每天的注册用户数,可以通过这些指标来看KPI完成情况。所以累计的计算也是笔试中经常出现的题目,下面通过一个案例讲解如何计算累计,抛砖引玉,希望大家能举一反三。
记录每个商品每天销售量的表sale_info如下图:
需求:使用SQL统计出每个商品截至每个月的累积销量。
第1步:计算每个商品每个月的销量
为了方便后面的讲解,我们把这一步操作的结果存在临时表tmp中,第1步我们先计算每个商品每个月的销量。
create table tmp as
select
product_id,
substring(sale_date,1,7) sale_month,
sum(quantity) month_quantity
from sale_info
group by
product_id,
substring(sale_date,1,7);
查询结果:
第2步:按月累计计算销量
到这一步,我们用sum开窗函数,对userid进行分组、按照月份进行排序即可完成累计销量的计算。
select
product_id,
sale_month,
month_quantity,
sum(month_quantity) over(
partition by product_id
order by sale_month) month_all
from tmp;
查询结果:
完整的SQL代码如下:
select
product_id,
sale_month,
month_quantity,
sum(month_quantity) over(
partition by product_id
order by sale_month) month_all
from
(
select
product_id,
substring(sale_date,1,7)sale_month,
sum(quantity) month_quantity
from sale_info
group by product_id,
substring(sale_date,1,7)
)t;
04、去除最高最低的平均
salary_info表记录了每个员工的月工资以及所属的部门,包含EmpId(员工ID)、Department(部门名称)、Salary(月工资)。
需求:计算除去部门最高工资,和最低工资的平均工资(字节跳动面试)。
因为要在每个部门内计算平均工资,但是要去除该部门的最高工资和最低工资,所以我们可以考虑使用窗口函数,按照部门进行分组,但是如何将部门的最高工资和最低工资去除呢?我们可以对分组后的数据按照工资分别顺序和逆序进行排序,排名第一的就分别是该部门最低和最高工资,将这2个排名第一的记录去除就是我们要计算的平均工资。
核心是使用窗口函数RANK分别对工资salary进行升序和降序排列,就获得了该分组内最低和最高的工资,过滤掉这2条记录再对工资salary进行平均avg即可。
完整SQL代码如下:
select a.department,avg(a.salary)
from
(
select *,
rank() over( partition by department
order by salary ) rank_asc,
rank() over( partition by department
order by salary desc) rank_desc
from emp
) a
group by a.department
where a.rank_asc >1
and a.rank_desc >1
面试或者笔试的过程中会设定各种各样的场景,在这些场景下考查我们SQL的查询能力,但是万变不离其宗,业务场景只是一个表现形式,抽象为SQL问题后其实基本上就是我们这篇文章介绍的几类问题:计算累计、连续,分类TopN等。只要掌握这些问题的解法,并且可以举一反三,并不需要盲目的花费大量的时间精力去刷题,多总结多思考,你就很容易在面试笔试环节脱颖而出了。
以上就是数据分析面试—SQL高频笔试题系列第2篇的内容,部分数据分析面试笔试请翻看历史文章,更多数据分析干货文章持续更新中,敬请期待,如果觉得不错,也欢迎分享、点赞和点在看哈