美文网首页
笔试题目(一)——2020学霸批拼多多数据分析笔试总结

笔试题目(一)——2020学霸批拼多多数据分析笔试总结

作者: kaka22 | 来源:发表于2020-07-29 16:01 被阅读0次

    引用: 2020学霸批拼多多数据分析笔试总结
    拼多多2020学霸批数据分析师笔试 —— SQL整理

    参考这个里边的题目 自己试着做一下 看看自己sql的水平怎么样

    第一部分:SQL查询题3道

    问题一:

    (考点:活动运营数据分析)


    表1——订单表orders,大概字段有(user_id‘用户编号’, order_pay‘订单金额’ , order_time‘下单时间’)。(图中字段名有些差异)

    表2——活动报名表act_apply,大概字段有(act_id‘活动编号’, user_id‘报名用户’,act_time‘报名时间’)

    要求:

    1. 统计每个活动对应所有用户在报名后产生的总订单金额,总订单数。(每个用户限报一个活动,题干默认用户报名后产生的订单均为参加活动的订单)。

    2. 统计每个活动从开始后到当天(考试日)平均每天产生的订单数,活动开始时间定义为最早有用户报名的时间。(涉及到时间的数据类型均为:datetime)。

    解答

    第一问

    select A.act_id, sum(O.order_pay) as total_pay, count(O.user_id) as order_count
    from orders as O
    left join act_apply as A
    on A.user_id = O.user_id
    group by A.act_id
    

    存在的问题: 少考虑了一个因素 订单时间应当超过活动时间 且别名起成中文会好一些

    select A.act_id as '活动编号', sum(O.order_pay) as '总金额', count(O.user_id) as '订单数'
    from orders as O
    left join act_apply as A
    on A.user_id = O.user_id
    where A.act_time  <= O.order_time
    group by A.act_id;
    

    第二问

    先选出每个活动开始的时间

    select A.act_id, min(A.act_time) as 'act_start' 
    from act_apply as A
    group by A.act_id;
    

    第一问可以得到总订单数 两表连接

    select tmp1.act_id as  '活动编号', tmp1.order_num/datediff(now(), tmp2.'act_start' ) as '活动开始后平均每天下单数'
    from (select A.act_id , count(O.user_id) as 'order_num'
    from orders as O
    left join act_apply as A
    on A.user_id = O.user_id
    where A.act_time  <= O.order_time
    group by A.act_id) as tmp1
    join (select A.act_id, min(A.act_time) as 'act_start' 
    from act_apply as A
    group by A.act_id) as tmp2
    on tmp1.act_id = tmp2.act_id
    

    整体思路就是 两个子查询 第一个先查出每个活动的订单数量 第二个查出每个订单的开始日期 两表按照活动id连接 每个订单的数量除以 当前日期与开始日期的差值即可
    (应该是对的)

    后边发现自己的写法写复杂了 其实第二个子查询是没必要的

    select A.act_id as  '活动编号', count(O.user_id)/datediff(now(), min(A.act_time))  as '活动开始后平均每天下单数' 
    from orders as O
    left join act_apply as A
    on A.user_id = O.user_id
    where A.act_time  <= O.order_time
    group by A.act_id
    

    作者的答案 其实也写复杂了但是可以学习一下窗口函数

    SELECT act_id as '活动编号', COUNT(*)/DATEDIFF(NOW(),act_start) AS '活动开始后平均每天下单数'
    FROM orders a
    LEFT JOIN
    (SELECT user_id ,act_id ,act_time, min(act_time) over(PARTITION by act_id) as 'act_start'
    FROM act_apply
    ) b
    ON a.user_id=b.user_id
    WHERE order_time>=act_time
    GROUP BY act_id,act_start
    

    这里用到了一个over函数 具体用法在后边进行了补充
    这个的思路与第一问的思路一致 只不过对于活动表给出了每个活动的开始日期(使用over比较方便 否则需要group by min 然后再做一次连接) 然后两表连接 分组计数除以时间差即可
    需要注意的是 我也觉得最后一行GROUP BY act_id,act_start 可以改为 GROUP BY act_id 但是作者给出了解释:

    如果group by 没有act_start的话 sql不允许select语句使用它的~是聚合函数的限制

    补充
    https://kknews.cc/code/66jnqzv.html
    OVER的定义
    OVER用于为行定义一个窗口,它对一组值进行操作,不需要使用GROUP BY子句对数据进行分组,能够在同一行中同时返回基础行的列和聚合列。

    OVER的语法

    OVER ( [ PARTITION BY column ] [ ORDER BY culumn ] )

    PARTITION BY 子句进行分组;
    ORDER BY 子句进行排序。
    窗口函数OVER()指定一组行,开窗函数计算从窗口函数输出的结果集中各行的值。
    开窗函数不需要使用GROUP BY就可以对数据进行分组,还可以同时返回基础行的列和聚合列。

    OVER的用法
    OVER开窗函数必须与聚合函数或排序函数一起使用,聚合函数一般指SUM(),MAX(),MIN,COUNT(),AVG()等常见函数。排序函数一般指RANK(),ROW_NUMBER(),DENSE_RANK(),NTILE()等。

    具体例子可以参考以上链接

    问题二:

    (考点:用户行为路径分析)


    表1——用户行为表tracking_log,大概字段有(user_id‘用户编号’,opr_id‘操作编号’,log_time‘操作时间’)

    要求:
    1.计算每天的访客数和他们的平均操作次数。
    2.统计每天符合以下条件的用户数:A操作之后是B操作,AB操作必须相邻。

    解答
    问题1:
    先选出每天的访客数和每天的操作次数

    select T.log_time, count(distinct T.user_id) as '访客数', count(T.opr_id) as '总操作次数'
    from tracking_log as T
    group by T.log_time
    

    子查询

    select tmp.log_time, tmp.'访客数', tmp.'总操作次数'/tmp.'访客数' as '平均操作次数'
    from (select T.log_time, count(distinct T.user_id) as '访客数', count(T.opr_id) as '总操作次数'
    from tracking_log as T
    group by T.log_time) as tmp;
    

    好像又写复杂了。。 不用子查询就可以完成

    select T.log_time, count(distinct T.user_id) as '访客数', count(T.opr_id)/count(distinct T.user_id) as '平均操作次数'
    from tracking_log as T
    group by T.log_time
    

    参考答案

    SELECT b.date ,  COUNT(b.user_id) as '访客数' , AVG(op) AS '平均操作次数'
    FROM
    (SELECT user_id , COUNT(opr_type) as 'op', CONVERT(log_time,date) as 'date' FROM tracking_log
    GROUP BY user_id,date) b
    GROUP BY b.date
    

    思路:用group嵌套,刚好可以把人数和人次分解开
    子查询对日期和user_id进行分组 得到每天每个人的操作次数
    然后对日期进行分组 统计user_id的数量即为每天的访客数 对每天每个人的操作次数取平均即为平均操作次数

    需要注意的点:
    MySQL 的CAST()和CONVERT()函数可用来获取一个类型的值,并产生另一个类型的值。两者具体的语法如下:

    CAST(value as type);
    CONVERT(value, type);

    这里的log_time需要用 CONVERT(log_time,date) as 'date' 处理

    而且mysql的一个特点是group by 中的字段 是可以使用 select中的别名的

    MySQL extends standard SQL to permit noncolumn expressions in GROUP BY clauses and considers the preceding statement valid.

    修改自己的答案

    select CONVERT(T.log_time,date) , count(distinct T.user_id) as '访客数', count(T.opr_id)/count(distinct T.user_id) as '平均操作次数'
    from tracking_log as T
    group by CONVERT(T.log_time,date) 
    

    问题2:
    刷过leetcode之后这个题还是比较简单的 就是写起来有些复杂
    先对时间排序对于不同的user_id创建按时间排序的rank

    select T.user_id, CONVERT(T.log_time,date) as date, T. opr_id,
    @rank:= if(T.user_id = @pre_id,  @rank+1, 1),
    @pre_id:= T.user_id 
    from tracking_log as T, (select @rank:=0, @pre_id:=NULL) as init
    -- Mysql,order by 后跟 别名 表达式 均可
    order by T.user_id, CONVERT(T.log_time,date) asc;
    

    然后两个上表进行连接 连接条件是user_id相等 tmp1.rank = tmp2.rank-1 (其实就是对于同一个user_id通过rank后后一天进行连接)
    然后筛选tmp1.opr_id = 'A' tmp2.opr_id = 'B'
    最后对日期分组计数即可 可能一天中用户先A后B多次 但只需要统计1次 因此需要去重

    select tmp1.date, count(distinct tmp1.user_id) as 'A-B路径用户计数' 
    from (select T.user_id, CONVERT(T.log_time,date) as date, T. opr_id,
    @rank:= if(T.user_id = @pre_id,  @rank+1, 1) as rank,
    @pre_id:= T.user_id 
    from tracking_log as T, (select @rank:=0, @pre_id:=NULL) as init
    order by T.user_id, CONVERT(T.log_time,date) asc) as tmp1
    join (select T.user_id, CONVERT(T.log_time,date) as date, T. opr_id,
    @rank:= if(T.user_id = @pre_id,  @rank+1, 1) as rank,
    @pre_id:= T.user_id 
    from tracking_log as T, (select @rank:=0, @pre_id:=NULL) as init
    order by T.user_id, CONVERT(T.log_time,date) asc)  as tmp2
    on tmp1.rank = tmp2.rank - 1 and tmp1.user_id = tmp2.user_id
    where tmp1.opr_id = 'A'  and tmp2.opr_id = 'B'
    group by tmp1.date;
    

    参考答案

    ELECT a.Date , COUNT(*) as 'A-B路径用户计数'
    FROM(
    SELECT DISTINCT user_id as 'User',opr_type as '1st', CONVERT(log_time,date) as 'Date', lead(opr_type,1) 
    over(PARTITION by user_id,CONVERT(log_time,date) ORDER BY log_time) as '2nd'
    FROM tracking_log
    ) a
    WHERE a.1st = 'A' and a.2nd ='B'
    GROUP BY a.Date
    

    确实利用窗口函数要简单很多
    对user_id,和时间分组 按时间排序 取出后一个操作opr_id的写法是这样的
    lag(1) 后移一项 lead(1)前移一项 这里应该用 lead

    select lead(T.opr_id) over( PARTITION by T.user_id,convert(T.log_time,date) order by T.log_time asc)
    from tracking_log as T
    

    整体选出是这样的 这里也需要去重

    SELECT DISTINCT T.user_id as 'User', T.opr_type as '1st', CONVERT(T.log_time,date) as 'Date', lead(T.opr_type,1) 
    over(PARTITION by T.user_id, CONVERT(T.log_time,date) ORDER BY CONVERT(T.log_time,date) ASC) as '2nd'
    FROM tracking_log as T
    

    最后剩下就是分组筛选 然后计数了

    问题三

    (考点:用户新增留存分析)

    表1——用户登陆表user_log,大概字段有(user_id‘用户编号’,log_time‘登陆时间’)

    要求:

    1.每天新增用户数,以及他们第2天、30天的回访比例

    参考答案:

    (找出每个用户第一次登陆时间,再聚合时间得到每一天新增用户,时间要聚合到天)

    解答
    先找出每个用户的最小日期即为首次登陆的时间

    select T.user_id, min(log_time) as first_time
    from tracking_log as T
    group by T.user_id
    

    又要再筛选 用一下窗口函数试一下吧

    select T.user_id, min(log_time) over(PARTITION by convert(T.user_id, date)) as first_time
    from tracking_log as T
    

    然后对first_time进行分组,统计去重的user_id个数即为当天的新用户数量

    select tmp.first_time, count(distinct tmp.user_id) as new_count
    from (select T.user_id, min(log_time) over(PARTITION by convert(T.user_id, date)) as first_time
    from tracking_log as T) as tmp
    group by tmp.first_time
    

    第二天的回访数量怎么求
    登陆时间与首次时间的差值为1就可以进行筛选

    select tmp1.first_time, count(distinct tmp1.user_id) as 2nd_back
    from (select T.user_id, min(log_time) over(PARTITION by convert(T.user_id, date)) as first_time, convert(T.user_id, date) as date
    from tracking_log as T) as tmp1
    where datediff(tmp1.date, tmp1.first_time) = 1
    group by tmp1.first_time
    

    同理 一个月后的回访

    select tmp2.first_time, count(distinct tmp2.user_id) as 30nd_back
    from (select T.user_id, min(log_time) over(PARTITION by convert(T.user_id, date)) as first_time, convert(T.user_id, date) as date
    from tracking_log as T) as tmp2
    where datediff(tmp2.date, tmp2.first_time) = 29
    group by tmp2.first_time
    

    以上三表进行连接 左连接

    select a.first_time as '日期', a.new_count as '新增用户',
    concat(round(100*b.2nd_back/a.new_count, 2), '%') as '第2天回访率'
    concat(round(100*b.30nd_back/a.new_count, 2), '%') as '第30天回访率' 
    from (select tmp.first_time, count(distinct tmp.user_id) as new_count
    from (select T.user_id, min(log_time) over(PARTITION by convert(T.user_id, date)) as first_time
    from tracking_log as T) as tmp
    group by tmp.first_time) as a
    left join (select tmp1.first_time, count(distinct tmp1.user_id) as 2nd_back
    from (select T.user_id, min(log_time) over(PARTITION by convert(T.user_id, date)) as first_time, convert(T.user_id, date) as date
    from tracking_log as T) as tmp1
    where datediff(tmp1.date, tmp1.first_time) = 1
    group by tmp1.first_time) as b
    on a.first_time = b.first_time
    left join (select tmp2.first_time, count(distinct tmp2.user_id) as 30nd_back
    from (select T.user_id, min(log_time) over(PARTITION by convert(T.user_id, date)) as first_time, convert(T.user_id, date) as date
    from tracking_log as T) as tmp2
    where datediff(tmp2.date, tmp2.first_time) = 29
    group by tmp2.first_time) as c
    on a.first_time = c.first_time
    

    第二部分:计算题1道

    问题四:

    (考点:贝叶斯公式的应用)

    已知A,B厂生产的产品的次品率分别是1%和2%,现在由A,B产品分别占60%、40%的样品中随机抽一件,若取到的是次品,求此次品是B厂生产的概率。

    第三部分:综合分析题1道

    问题五:

    (考点:产品更新决策的数据支持)

    某网站优化了商品详情页,现在新旧两个版本同时运行,新版页面覆盖了10%的用户,旧版覆盖90%的用户。现在需要了解,新版页面是否能够提高商品详情页到支付页的转化率,并决定是否要覆盖旧版,你能为决策提供哪些信息,需要收集哪些指标,给出统计方法及过程。

    这个是A/B test 的问题 先学习一下 再返回来看这个问题

    相关文章

      网友评论

          本文标题:笔试题目(一)——2020学霸批拼多多数据分析笔试总结

          本文链接:https://www.haomeiwen.com/subject/qcthrktx.html