-- ① 先算首周单量 → 给骑手打 tier
-- ② 统计每个 tier 的总人数(作为留存率分母)
-- ③ 找 W1/W2/W4 的订单,并打时间段标签
-- ④ 聚合出 active_rider_cnt + avg_duration
-- ⑤ 用 维度表 cross join 补全 36 行
-- ⑥ left join 聚合结果,空值补 0
-- Step1:构造时间窗口(首周 + 各留存周)
with r_date as (
select
rider_id,
reg_date,
date_add(reg_date,interval 6 day) as day_6, -- 首周结束
date_add(reg_date,interval 7 day) as day_7,
date_add(reg_date,interval 13 day) as day_13,
date_add(reg_date,interval 14 day) as day_14,
date_add(reg_date,interval 20 day) as day_20,
date_add(reg_date,interval 28 day) as day_28,
date_add(reg_date,interval 34 day) as day_34
from t_rider
),
-- Step2:筛选留存期订单 + 打标签(周 + 时段)
t1 as (
select
r.rider_id,
r.reg_date,
t.pickup_time,
t.deliver_time,
-- 留存周划分
case
when date(t.pickup_time) between r.day_7 and r.day_13 then 'W1'
when date(t.pickup_time) between r.day_14 and r.day_20 then 'W2'
when date(t.pickup_time) between r.day_28 and r.day_34 then 'W4'
end as retention_week,
-- 时段划分(按 pickup_time)
case
when time(t.pickup_time) between '06:00:00' and '10:59:59' then 'morning'
when time(t.pickup_time) between '11:00:00' and '13:59:59' then 'noon'
when time(t.pickup_time) between '17:00:00' and '20:59:59' then 'evening'
else 'night'
end as time_slot
from t_delivery t
join r_date r on t.rider_id = r.rider_id
where
t.status = 'FINISHED'
-- 只保留留存周订单
and (
date(t.pickup_time) between r.day_7 and r.day_13
or date(t.pickup_time) between r.day_14 and r.day_20
or date(t.pickup_time) between r.day_28 and r.day_34
)
),
-- Step3:计算首周单量 → 分层(T1/T2/T3)
t2 as (
select
r.rider_id,
r.reg_date,
case
when sum(case when date(t.pickup_time) between r.reg_date and r.day_6 then 1 else 0 end) >= 30 then 'T1'
when sum(case when date(t.pickup_time) between r.reg_date and r.day_6 then 1 else 0 end) >= 15 then 'T2'
when sum(case when date(t.pickup_time) between r.reg_date and r.day_6 then 1 else 0 end) >= 1 then 'T3'
end as tier
from t_delivery t
join r_date r on t.rider_id = r.rider_id
where t.status = 'FINISHED'
group by r.rider_id, r.reg_date
-- 剔除首周 0 单骑手
having sum(case when date(t.pickup_time) between r.reg_date and r.day_6 then 1 else 0 end) >= 1
),
-- Step4:计算每个 tier 的基准人数(留存率分母)
tier_base as (
select
tier,
count(distinct rider_id) as base_rider_cnt
from t2
group by tier
),
-- Step5:聚合留存指标(核心统计)
agg as (
select
t2.tier,
t1.retention_week,
t1.time_slot,
-- 在岗骑手数(至少1单)
count(distinct t1.rider_id) as active_rider_cnt,
-- 单均时效(分钟)
round(avg(timestampdiff(second,t1.pickup_time,t1.deliver_time) / 60.0),2) as avg_duration_min
from t1
join t2 on t1.rider_id = t2.rider_id
group by
t2.tier,
t1.retention_week,
t1.time_slot
),
-- Step6:构造维度表(保证输出36行)
t_tier as (
select 'T1' as tier
union all select 'T2'
union all select 'T3'
),
t_retention_week as (
select 'W1' as retention_week
union all select 'W2'
union all select 'W4'
),
t_time_slot as (
select 'morning' as time_slot, 1 as slot_order
union all select 'noon', 2
union all select 'evening', 3
union all select 'night', 4
)
-- Step7:拼接最终结果(补全缺失组合)
select
t_t.tier,
t_r.retention_week,
t_s.time_slot,
-- 在岗骑手数(无数据补0)
ifnull(agg.active_rider_cnt, 0) as active_rider_cnt,
-- 留存率 = 在岗骑手 / 基准骑手
round(ifnull(agg.active_rider_cnt, 0) / tier_base.base_rider_cnt, 2) as retention_rate,
-- 单均时效(无数据补0)
ifnull(agg.avg_duration_min, 0.00) as avg_duration_min
from t_tier t_t
cross join t_retention_week t_r
cross join t_time_slot t_s
join tier_base on t_t.tier = tier_base.tier
left join agg
on t_t.tier = agg.tier
and t_r.retention_week = agg.retention_week
and t_s.time_slot = agg.time_slot
-- 排序规则
order by
t_t.tier,
t_r.retention_week,
t_s.slot_order,
active_rider_cnt desc;