题解 | #每天的日活数及新用户占比#

每天的日活数及新用户占比

http://www.nowcoder.com/practice/dbbc9b03794a48f6b34f1131b1a903eb

明确题意

统计每天的日活数新用户占比

步骤拆解

1. 得到客户最早进入时间表 tb_early

  • 最早活跃时间:MIN(DATE(in_time))
			SELECT uid,MIN(DATE(in_time)) early_time
			FROM tb_user_log ul
			GROUP BY uid

2. 得到客户所有的活跃时间表 tb_uv

SELECT 
  uid,
  DATE(in_time) uv_time -- 客户进入时间
FROM
  tb_user_log ul 
UNION -- 将两个表UNION,去重得到客户的所有活跃时间(跨天按两天算)
SELECT 
  uid,
  DATE(out_time) uv_time -- 客户退出时间 
FROM
  tb_user_log ul 

3. 将表 tb_early 与表 tb_uv 左连得到新表 tb 包括客户最早活跃时间(即哪天为新用户),活跃时间

SELECT 
    tb_early.uid,
    uv_time,
    early_time 
FROM tb_early 
LEFT JOIN tb_uv 
ON tb_early.uid = tb_uv.uid -- 将最早进入时间与所有活跃时间连接起来

4. 对 tb 按活跃时间进行分组,计算每天的活跃数,以及新用户数

  • 按照活跃时间分组:GROUP BY uv_time
  • 每天的活跃数: COUNT( DISTINCT uid ) dau
  • 新用户数:SUM(IF( early_time=uv_time,1,0))
  • 新用户占比 = 新用户数 / 每天的活跃数
  • 保留两位小数:ROUND(uv_new,2)
 SELECT 
	tb.uv_time dt,
    COUNT(DISTINCT uid) dau, -- 计算每天的用户数
    ROUND(SUM(IF( early_time=uv_time,1,0))/COUNT(DISTINCT uid),2) nu_new_ratio
    -- 如果最早进入时间=活跃时间,则认为是新用户
 FROM tb -- tb表有客户id,客户最早进入时间,客户活跃时间
 GROUP BY uv_time -- 按活跃时间分组
 ORDER BY dt -- 按日期升序

最终代码

 SELECT 
	tb.uv_time dt,
    COUNT(DISTINCT uid) dau, -- 计算每天的用户数
    ROUND(SUM(IF( early_time=uv_time,1,0))/COUNT(DISTINCT uid),2) nu_new_ratio
    -- 如果最早进入时间=活跃时间,则认为是新用户
  FROM 
  (
	  SELECT tb_early.uid,uv_time,early_time
	  FROM ( -- 客户最早进入时间
			SELECT uid,MIN(DATE(in_time)) early_time
			FROM tb_user_log ul
			GROUP BY uid
	  ) tb_early
	  LEFT JOIN 
	  (   
		  SELECT uid,DATE(in_time) uv_time
		  FROM tb_user_log ul -- 客户进入时间
		  UNION -- 将两个表UNION,去重得到客户的所有活跃时间(跨天按两天算)
		  SELECT uid,DATE(out_time) uv_time
		  FROM tb_user_log ul -- 客户退出时间
		) tb_uv
		ON tb_early.uid=tb_uv.uid  -- 将最早进入时间与所有活跃时间连接起来
  ) tb -- tb表有客户id,客户最早进入时间,客户活跃时间
  GROUP BY uv_time -- 按活跃时间分组
  ORDER BY dt -- 按日期升序

优化代码1.0

可以把最早进入时间利用窗口函数直接计算,就不用连接俩表了

  SELECT 
    tb.uv_time dt,
    COUNT(DISTINCT uid) dau,
    -- 计算每天的用户数
    ROUND(
      SUM(IF(early_time = uv_time, 1, 0)) / COUNT(DISTINCT uid),
      2
    ) nu_new_ratio -- 如果最早进入时间=活跃时间,则认为是新用户
  FROM
    (SELECT 
      uid,
      uv_time,
      (MIN(uv_time) over (PARTITION BY uid)) early_time  -- 最早进入时间
    FROM
      (SELECT 
        uid,
        DATE(in_time) uv_time 
      FROM
        tb_user_log ul -- 客户进入时间
      UNION
      -- 将两个表UNION,去重得到客户的所有活跃时间(跨天按两天算)
      SELECT 
        uid,
        DATE(out_time) uv_time 
      FROM
        tb_user_log ul -- 客户退出时间
      ) tb_uv -- 将最早进入时间与所有活跃时间连接起来
    ) tb -- tb表有客户id,客户最早进入时间,客户活跃时间
  GROUP BY uv_time -- 按活跃时间分组
  ORDER BY dt -- 按日期升序 
全部评论

相关推荐

不愿透露姓名的神秘牛友
07-11 11:29
点赞 评论 收藏
分享
05-29 22:11
门头沟学院 Java
Elastic90:抛开学历造假不谈,这公司的招聘需求也挺怪的,Java开发还要求你有图文识别、移动端开发和c++的经验,有点逆天了。
点赞 评论 收藏
分享
05-21 15:47
门头沟学院 Java
浪漫主义的虹夏:项目有亮点吗,第一个不是纯玩具项目吗,项目亮点里类似ThreadLocal,Redis储存说难听点是花几十分钟绝大部分人都能学会,第二个轮子项目也没体现出设计和技术,想实习先沉淀,好高骛远的自嗨只会害了自己
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-09 12:02
ssob上原来真有BOSS啊
硫蛋蛋:这种也是打工的,只不是是给写字楼房东打工
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务