SQL面试题-留存率计算

表定义: 

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

 

方法一:

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

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

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

# 按照用户的访问时间进行排序
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天留存需要增加代码量

-- 计算次日留存率
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;

### SQL 次日留存率计算方法及面试题解答 次日留存率是衡量用户在首次登录后的第二天是否继续使用产品的指标。它对于评估产品的吸引力和用户的粘性具有重要意义[^2]。以下是次日留存率计算方法及相关SQL面试题的解答。 #### 1. 次日留存率的定义 次日留存率是指在某一天新增的用户中,有多少比例的用户在第二天再次登录系统。公式如下: \[ 次日留存率 = \frac{次日再次登录的用户数}{新增用户数} \times 100\% \] #### 2. 计算次日留存率SQL实现 以下是一个通用的SQL实现方式,用于计算次日留存率: ```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 FROM user_log a JOIN FirstLogin b ON a.user_id = b.user_id WHERE DATE(a.record_time) = DATE(DATE_ADD(b.first_record_time, INTERVAL 1 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; ``` 上述代码通过两个CTE(Common Table Expressions)分别找出首次登录的用户和次日再次登录的用户,然后通过连接操作计算次日留存率[^4]。 #### 3. 面试题示例 **题目:** 给定一张记录用户登录信息的表`user_log`,包含字段`user_id`(用户ID)和`record_time`(登录时间)。请编写SQL查询,计算每天新增用户的次日留存率。 **解答:** ```sql WITH DailyNewUsers AS ( -- 找出每天新增的用户 SELECT user_id, record_time AS first_login_date FROM ( SELECT user_id, record_time, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY record_time) AS rn FROM user_log ) t WHERE rn = 1 ), NextDayLogins AS ( -- 找出次日登录的用户 SELECT a.user_id, a.record_time FROM user_log a JOIN DailyNewUsers b ON a.user_id = b.user_id WHERE DATE(a.record_time) = DATE(DATE_ADD(b.first_login_date, INTERVAL 1 DAY)) ) -- 计算每天新增用户的次日留存率 SELECT DATE(b.first_login_date) AS login_date, COUNT(DISTINCT a.user_id) AS next_day_retention_users, COUNT(DISTINCT b.user_id) AS new_users, ROUND(COUNT(DISTINCT a.user_id) / COUNT(DISTINCT b.user_id) * 100, 2) AS next_day_retention_rate FROM NextDayLogins a RIGHT JOIN DailyNewUsers b ON a.user_id = b.user_id GROUP BY DATE(b.first_login_date); ``` 此查询首先通过窗口函数`ROW_NUMBER()`找出每天新增的用户,然后计算这些用户在次日再次登录的比例[^3]。 --- ### 知识点总结 - **时间函数:** 使用`MIN()`、`DATE()`、`DATE_ADD()`等函数处理日期数据。 - **窗口函数:** 使用`ROW_NUMBER()`标记每个用户的首次登录记录。 - **连接操作:** 使用`JOIN`或`LEFT JOIN`将首次登录用户与次日登录用户进行匹配。 - **聚合函数:** 使用`COUNT()`统计用户数量,并结合`ROUND()`函数计算百分比。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值