当前位置: 首页 > news >正文

SQL164 2021年11月每天新用户的次日留存率

SQL164 2021年11月每天新用户的次日留存率

思路

  1. 找出新用户​:确定每个用户首次活跃的日期(即新用户)

    • 例如101用户在11月1日首次出现
  2. 处理跨天活跃​:考虑用户可能跨天活跃的情况(in_time和out_time不在同一天)

    • 例如用户可能在11月1日23:50进入,11月2日00:10离开,则算作两天都活跃
  3. 计算次日留存​:

    • 对每个新用户,检查他们首次活跃后的第二天是否仍然活跃
    • 使用LEAD窗口函数高效获取用户下一次活跃日期
  4. 计算留存率​:

    • 每天的新用户数作为分母
    • 第二天仍然活跃的新用户数作为分子
    • 两者相除得到留存率,保留2位小数

最终输出2021年11月每天新用户的次日留存率,按日期排序。

代码

WITH 
-- 获取每个用户的最早活跃日期作为其首次出现日期
first_occurrence AS (SELECT uid,DATE(MIN(in_time)) AS first_dtFROM tb_user_logGROUP BY uid
),-- 获取每个用户每天活跃的记录(处理跨天情况)
user_active_dates AS (SELECT DISTINCT uid,DATE(in_time) AS active_dateFROM tb_user_logUNIONSELECT DISTINCT uid,DATE(out_time) AS active_dateFROM tb_user_log
),-- 为每个用户按日期排序,并使用LEAD获取下一天的活跃状态
user_activity_sequence AS (SELECT uid,active_date,LEAD(active_date) OVER (PARTITION BY uid ORDER BY active_date) AS next_active_dateFROM user_active_dates
),-- 计算每天的新用户数及其次日留存情况
daily_stats AS (SELECT fo.first_dt AS dt,COUNT(DISTINCT fo.uid) AS new_users,COUNT(DISTINCT CASE WHEN DATEDIFF(uas.next_active_date, fo.first_dt) = 1 THEN fo.uid END) AS retained_usersFROM first_occurrence foLEFT JOIN user_activity_sequence uas ON fo.uid = uas.uid AND fo.first_dt = uas.active_dateWHERE fo.first_dt BETWEEN '2021-11-01' AND '2021-11-30'GROUP BY fo.first_dt
)-- 计算并格式化留存率
SELECT dt,ROUND(IF(new_users = 0, 0, retained_users / new_users), 2) AS uv_left_rate
FROM daily_stats
ORDER BY dt;

逐步展示如何计算2021年11月每天新用户的次日留存率

原始数据表 tb_user_log

iduidartical_idin_timeout_timesign_in
110102021-11-01 10:00:002021-11-01 10:00:421
210290012021-11-01 10:00:002021-11-01 10:00:090
310390012021-11-01 10:00:012021-11-01 10:01:500
410190022021-11-02 10:00:092021-11-02 10:00:280
510390022021-11-02 10:00:512021-11-02 10:00:590
610490012021-11-02 10:00:282021-11-02 10:00:500
710190032021-11-03 11:00:552021-11-03 11:01:240
810490032021-11-03 11:00:452021-11-03 11:00:550
910590032021-11-03 11:00:532021-11-03 11:00:590
1010190022021-11-04 11:00:552021-11-04 11:00:590

步骤1:确定每个用户的首次活跃日期

SELECT uid,DATE(MIN(in_time)) AS first_dt
FROM tb_user_log
GROUP BY uid;

结果:

uidfirst_dt
1012021-11-01
1022021-11-01
1032021-11-01
1042021-11-02
1052021-11-03

步骤2:处理跨天情况,获取用户活跃日期

SELECT DISTINCT uid,DATE(in_time) AS active_date
FROM tb_user_log
UNION
SELECT DISTINCT uid,DATE(out_time) AS active_date
FROM tb_user_log;

结果:

uidactive_date
1012021-11-01
1012021-11-02
1012021-11-03
1012021-11-04
1022021-11-01
1032021-11-01
1032021-11-02
1042021-11-02
1042021-11-03
1052021-11-03

步骤3:使用LEAD函数获取用户的下一次活跃日期

SELECT uid,active_date,LEAD(active_date) OVER (PARTITION BY uid ORDER BY active_date) AS next_active_date
FROM user_active_dates;

结果:

uidactive_datenext_active_date
1012021-11-012021-11-02
1012021-11-022021-11-03
1012021-11-032021-11-04
1012021-11-04NULL
1022021-11-01NULL
1032021-11-012021-11-02
1032021-11-02NULL
1042021-11-022021-11-03
1042021-11-03NULL
1052021-11-03NULL

步骤4:计算每天的新用户次日留存情况

SELECT fo.first_dt AS dt,COUNT(DISTINCT fo.uid) AS new_users,COUNT(DISTINCT CASE WHEN DATEDIFF(uas.next_active_date, fo.first_dt) = 1 THEN fo.uid END) AS retained_users
FROM first_occurrence fo
LEFT JOIN user_activity_sequence uas ON fo.uid = uas.uid AND fo.first_dt = uas.active_date
WHERE fo.first_dt BETWEEN '2021-11-01' AND '2021-11-30'
GROUP BY fo.first_dt;

结果:

dtnew_usersretained_users
2021-11-0132
2021-11-0211
2021-11-0310

详细解释一下

这个CTE是计算每日新用户及其次日留存情况的核心部分,详细拆解逻辑:

  1. 数据来源​:

    • first_occurrence:包含每个用户的首次活跃日期
    • user_activity_sequence:包含用户每次活跃日期及下一次活跃日期(使用LEAD计算)
  2. 连接条件​:

    LEFT JOIN user_activity_sequence uas 
    ON fo.uid = uas.uid 
    AND fo.first_dt = uas.active_date
    • 按用户ID连接
    • 只连接用户首次活跃当天的记录(因为我们要计算的是新用户的次日留存)
  3. 计算字段​:

    • new_users:每天首次出现的用户数(COUNT DISTINCT)
    • retained_users:这些新用户中第二天仍然活跃的数量
  4. 留存判断逻辑​:

    CASE WHEN DATEDIFF(uas.next_active_date, fo.first_dt) = 1 THEN fo.uid 
    END
    • 计算用户首次活跃日期与下一次活跃日期的差值
    • 如果差值为1天,则表示用户次日活跃
  5. 为什么用LEFT JOIN​:

    • 确保即使新用户第二天不活跃,也会被计入分母(新用户数)
    • 不活跃的用户在CASE WHEN中会返回NULL,不会被COUNT计算

示例数据推演

以2021-11-01为例:

  • 新用户:101、102、103
  • 检查他们的次日活跃情况:
    • 101:11-02活跃(符合)
    • 102:11-02不活跃
    • 103:11-02活跃(符合)
  • 结果:3个新用户,2个次日活跃 → 留存率2/3=0.67

这种设计确保了:

  1. 准确识别新用户
  2. 正确处理跨天活跃情况
  3. 精确计算次日留存率

最终结果:计算留存率

SELECT dt,ROUND(IF(new_users = 0, 0, retained_users / new_users), 2) AS uv_left_rate
FROM daily_stats
ORDER BY dt;

最终输出:

dtuv_left_rate
2021-11-010.67
2021-11-021.00
2021-11-030.00

http://www.lryc.cn/news/599212.html

相关文章:

  • 虚拟地址-物理地址
  • 关于“PromptPilot”
  • jwt 验证方法 (ASP.NET Core)
  • Uniapp编写微信小程序,绘制动态圆环进度条
  • Linux——线程(下)
  • uniapp小程序上传图片并压缩
  • 【MacOS】发展历程
  • 基于 Nginx 与未来之窗防火墙构建下一代自建动态网络防护体系​—仙盟创梦IDE
  • 好看的小程序推广单页HTML源码 可用作导航页
  • 校园二手交易小程序的设计与实现
  • 如何将荣耀手机的照片传输到 Mac
  • 小程序安卓ApK转aab文件详情教程MacM4环境
  • Linux 时间同步的流程
  • 小程序卡顿到丝滑体验:ZKmall开源商城性能优化与兼容修复实战指南
  • 教培机构如何开发自己的证件照拍照采集小程序
  • 【pybind11】 pybind11如何调用python
  • 《整合Spring Cache:本地缓存、Redis与Caffeine对比实践》
  • Python 数据可视化之 Matplotlib 库
  • 【国内电子数据取证厂商龙信科技】谁是躲在“向日葵”后的
  • OSPF之多区域
  • 【ResNet50图像分类部署至RK3588】模型训练→转换RKNN→开发板部署
  • Jmeter的元件使用介绍:(四)前置处理器详解
  • JMeter每次压测前清除全部以确保异常率准确(以黑马点评为例、详细图解)
  • Pytorch中register_buffer和torch.nn.Parameter的异同
  • npm init vite-app runoob-vue3-test2 ,npm init vue@latest,指令区别
  • LIMA:大语言模型对齐的“少即是多”革命——原理、实验与范式重构
  • VR 技术在污水处理领域的创新性应用探索​
  • 华为云DRS实现Oracle到GaussDB数据库迁移的全流程技术方案
  • GTSuite许可与网络安全
  • Android Studio 自带的官方模拟器,ABI这一列是x86_64,xABI这一列是arm64-v8a