SQL面试题-留存率计算

表定义:

sql 复制代码
create table if not exists liuliang_detail
(
    user_id string comment ''
    ,record_time string comment 'yyyymmdd hh:mi:ss'
)
comment '流量明细表'
;

方法一:

计算的是整段时间范围内,每一天为基准的所有的留存1、2、7天的用户数。

方法一的优势是可以一次性计算出,每天的不同时间范围的留存率。

但是不是很直观,并且计算量比较大。

sql 复制代码
# 按照用户的访问时间进行排序
create table if not exists liuliang_partition as
select a.user_id
       ,a.record_time
       ,row_number() over(partition by user_id order by record_time) rn_asc
       --,row_number() over(partition by user_id order by recordtime desc) rn_des
from liuliang_detail a
where date(record_time) >= '2021-01-01' -- 最好根据产品上线时间确定,要不然流量表太大,影响运行效率
;

# 计算整段时间范围内,以每天为基准的的留存率

select recorddate

       ,count(distinct user_id) total_uv

       ,count(distinct case when rn_asc = 1 then user_id else null end) new_uv -- 首次访问uv

       ,round(100*count(distinct case when rn_asc = 1 then user_id else null end)/count(distinct user_id), 1) new_uv_ratio -- 首次访问uv占比

       ,count(distinct case when rn_asc <> 1 and diff_days = 1 then user_id else null end) lastday_uv -- 次日留存

       ,count(distinct case when rn_asc <> 1 and diff_days = 2 then user_id else null end) last2day_uv -- 2日留存

       ,count(distinct case when rn_asc <> 1 and diff_days = 3 then user_id else null end) last3day_uv -- 3日留存

       ,count(distinct case when rn_asc <> 1 and diff_days = 4 then user_id else null end) last4day_uv -- 4日留存

       ,count(distinct case when rn_asc <> 1 and diff_days = 5 then user_id else null end) last5day_uv -- 5日留存

       ,count(distinct case when rn_asc <> 1 and diff_days = 6 then user_id else null end) last6day_uv -- 6日留存

       ,count(distinct case when rn_asc <> 1 and diff_days = 7 then user_id else null end) last7day_uv -- 7日留存

       ,count(distinct case when rn_asc <> 1 and diff_days = 14 then user_id else null end) last14day_uv -- 14日留存

       ,count(distinct case when rn_asc <> 1 and diff_days = 30 then user_id else null end) last30day_uv -- 30日留存

from

(

  select a.*

         ,date(record_time) recorddate

         ,datediff(cast(a.record_time as date), cast(b.record_time as date)) diff_days -- 留存天数

  from liuliang_partition a

  left join liuliang_partition b on a.user_id = b.user_id and a.rn_asc = b.rn_asc+1

) x

group by recorddate;

方法二:

计算的是用户首次登陆时间为基准时间,计算该基准时间之后的n日留存率。

优点:代码直观好理解

缺点:如果要计算n天留存需要增加代码量

sql 复制代码
-- 计算次日留存率
WITH FirstLogin AS (
    -- 找出每个用户的首次登录时间
    SELECT
        user_id,
        MIN(record_time) AS first_record_time
    FROM
        user_log
    GROUP BY
        user_id
),
RetentionUsers AS (
    -- 找出次日登录的用户
    SELECT
        a.user_id,
        a.record_time,
        DATE_ADD(b.first_record_time, INTERVAL 1 DAY) AS expected_next_day
    FROM
        user_log a
    JOIN
        FirstLogin b ON a.user_id = b.user_id
    WHERE
        DATE(a.record_time) = DATE(expected_next_day)
)
-- 计算留存率
SELECT
    COUNT(DISTINCT RetentionUsers.user_id) AS next_day_retention_users,
    COUNT(DISTINCT FirstLogin.user_id) AS initial_users,
    ROUND(COUNT(DISTINCT RetentionUsers.user_id) / COUNT(DISTINCT FirstLogin.user_id) * 100, 2) AS next_day_retention_rate
FROM
    FirstLogin
LEFT JOIN
    RetentionUsers ON FirstLogin.user_id = RetentionUsers.user_id;
相关推荐
梁bk8 分钟前
苍穹外卖项目总结(一)[MyBatis-Plus,文件上传,Redis]
数据库·redis·mybatis
CNRio9 分钟前
Redis:内存中的数据引擎,架构解析与设计指南
数据库·redis·架构
hans汉斯10 分钟前
【软件工程与应用】基于大数据的应急救援云平台构建应用研究
大数据·数据库·人工智能·物联网·系统架构·云计算·汉斯出版社
流绪染梦13 分钟前
多表联查时处理一对多的信息,将子表字段放入数组
java·数据库
悦数图数据库18 分钟前
国产图数据库:开启数据新“视”界 悦数科技
数据库·人工智能
啊巴矲21 分钟前
小白从零开始勇闯人工智能Linux初级篇(Navicat Premium及MySQL库(安装与环境配置))
数据库·人工智能·mysql
en-route23 分钟前
Redis 作为消息队列的三种使用方式与 Spring Boot 实践
数据库·spring boot·redis
GreatSQL社区26 分钟前
GreatSQL MGR三节点基于时间点恢复
数据库·oracle
李慕婉学姐28 分钟前
Springboot遇见宠物生活馆系统设计与实现n6ea5118(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·宠物
2501_9419820531 分钟前
企业微信客户联系API中 添加客户 与 发送欢迎语 的异步处理优化
服务器·数据库·php