Bootstrap

【SQL 09 2022年SHEIN面试题 - 品类会员数】

题目描述

请计算每个月不同品类不同类型用户的用户数量
用户类型如下:

  • 品类新会员数: 统计月当月首次购买X品类的用户数
  • 品类老会员数: 截止到统计月之前,购买过X品类的用户数
  • 品类老会员复购数: 截止到统计月之前购买过X品类,且在统计月内再次购买X品类的用户数
  • 当期新会员转化数: 当期新会员(首次消费在统计月内的用户数)中,有多少用户购买了X品类
  • 品类历史新会员数: 截止到统计月之前,历史曾经发生过购买行为但没有购买X品类的用户数
  • 品类历史新会员转化数: 品类历史新会员中,有多少用户购买了X品类
全量销售明细表 dw_oder_detail_df:
字段名字段类型字段含义
pay_timevarchar付款日期(yyyy-MM-dd HH:mm:ss格式,假设一个用户同一秒中只能支付一个订单)
skuvarchar商品名称
user_idvarchar用户ID
cate_nmvarchar商品对应的品类
最终输出样式:

以2021-12月为例(实际SQL结果应包括所有月份),品类只有A,B,C三个,则数据的输出格式为:

月份品类品类新会员数品类老会员数品类老会员复购数当期新会员转化数品类历史新会员数品类历史新会员转化数
2021-12A1001000300202000080
2021-12B1001000300202000080
2021-12C1001000300202000080
2021-12A解释:表示12月当月有100个人第一次购买X品类解释:截止11月底,总共有1000个人买过X品类解释:左侧1000人中,12月有300人又买了X品类解释:首次购买在本月的用户中,有20个人在首单月购买了X品类解释:截止到11月底,总共又2W个购买过用户没有买过A品类的用户解释:左侧2W用户中,有80人在12月第一次买了A品类

题目分析

首先我们对于6个指标口径观察:
1.“品类新会员数” 和 “品类老会员数” 的关系就是通过——会员首次购买该品类动作发生的月份来区分。
2.“品类老会员复购数” 、 “当期新会员转化数” 、“品类历史新会员数”、“品类历史新会员转化数”的关系通过——对比会员首次购买该品类的月份和会员各月份某品类是否购买来区分的。
因此,我们核心就是查询:会员首次购买某品类月份 、 会员每个月份每个品类该品类的购买情况 以及 会员首次购买的月份。
品类新会员数 :该品类该会员的购买月份 = 该品类该会员的首次购买月份
品类老会员数 :该品类该会员的购买月份 > 该品类该会员的首次购买月份

SQL实现

一、会员首次购买某品类月份 first_month_for_cate_user & 会员首次购买月份 fisrt_month_for_user
SELECT
	*,
	FIRST_VALUE( stat_month ) OVER ( PARTITION BY user_id ORDER BY stat_month ) first_month_for_user,
	FIRST_VALUE( stat_month ) OVER ( PARTITION BY user_id, cate_nm ORDER BY stat_month ) first_month_for_cate_user 
FROM
	( 
	SELECT DISTINCT substr( pay_time, 1, 7 ) stat_month, user_id, cate_nm FROM dw_order_detail_df 
	) ddf1
GROUP BY
		ddf1.stat_month,
		ddf1.cate_nm 
  • ddf1是根据"2021-12"的形式处理了订单日期,得到订单月份(stat_month)、用户ID(user_id)、品类(cate_nm)的去重后数据表。
  • 按照订单月份、品类 分类聚合,通过 first_vlaue 窗口函数获得fisrt_month_for_user、first_month_for_cate_user。
二、会员每个月份每个品类该品类的购买情况
SELECT
	t1.stat_month `月份`,
	t1.cate_nm `品类`,
	t1.new_buy_cate_user_cnt `品类新会员数`,
	count( DISTINCT t3.user_id ) `品类老会员数`,
	t1.old_buy_cate_user_cnt `品牌老会员复购数`,
	t1.new_buy_cate_new_user_cnt `当期新会员转化数`,
	count( DISTINCT t2.user_id ) - count( DISTINCT t3.user_id ) `品类历史新会员数`,
	t1.new_buy_cate_old_user_cnt `品类历史新会员转化数` 
FROM
	(
	SELECT
		stat_month,
		cate_nm,
		count( CASE WHEN stat_month = first_month_for_cate_user THEN 1 END ) new_buy_cate_user_cnt,
		count( CASE WHEN stat_month > first_month_for_cate_user THEN 1 END ) old_buy_cate_user_cnt,
		count( CASE WHEN stat_month = first_month_for_cate_user AND stat_month = first_month_for_user THEN 1 END ) new_buy_cate_new_user_cnt,
		count( CASE WHEN stat_month = first_month_for_cate_user AND stat_month > first_month_for_user THEN 1 END ) new_buy_cate_old_user_cnt 
	FROM
		(
		SELECT
			*,
			first_value( stat_month ) over ( PARTITION BY user_id ORDER BY stat_month ) first_month_for_user,
			first_value( stat_month ) over ( PARTITION BY user_id, cate_nm ORDER BY stat_month ) first_month_for_cate_user 
		FROM
			( SELECT DISTINCT substr( pay_time, 1, 7 ) stat_month, user_id, cate_nm FROM dw_order_detail_df ) ddf1
		) ddf2
	GROUP BY
		stat_month,
		cate_nm 
	) t1
	LEFT JOIN ( SELECT DISTINCT substr( pay_time, 1, 7 ) stat_month, user_id FROM dw_order_detail_df ) t2 ON t1.stat_month > t2.stat_month
	LEFT JOIN ( SELECT DISTINCT substr( pay_time, 1, 7 ) stat_month, user_id, cate_nm FROM dw_order_detail_df ) t3 ON t2.stat_month = t3.stat_month 
	AND t2.user_id = t3.user_id 
	AND t1.cate_nm = t3.cate_nm 
GROUP BY
	t1.stat_month,
	t1.cate_nm,
	t1.new_buy_cate_user_cnt,
	t1.old_buy_cate_user_cnt,
	t1.new_buy_cate_new_user_cnt,
	t1.new_buy_cate_old_user_cnt
;