首页 > 试题广场 >

零食类商品中复购率top3高的商品

[编程题]零食类商品中复购率top3高的商品
  • 热度指数:76840 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

商品信息表tb_product_info

id product_id
shop_id tag int_ quantity release_time
1 8001 901 零食 60 1000 2020-01-01 10:00:00
2 8002 901 零食 140 500 2020-01-01 10:00:00
3 8003 901 零食 160 500 2020-01-01 10:00:00
(product_id-商品ID, shop_id-店铺ID, tag-商品类别标签, in_price-进货价格, quantity-进货数量, release_time-上架时间)

订单总表tb_order_overall

id order_id uid event_time total_amount total_cnt status
1 301001 101 2021-09-30 10:00:00 140 1 1
2 301002 102 2021-10-01 11:00:00
235 2 1
3 301011 102 2021-10-31 11:00:00
250 2 1
4 301003 101 2021-10-02 10:00:00
300 2 1
5
301013 105 2021-10-02 10:00:00
300 2 1
6 301005 104 2021-10-03 10:00:00
170 1 1
(order_id-订单号, uid-用户ID, event_time-下单时间, total_amount-订单总金额, total_cnt-订单商品总件数, status-订单状态)


订单明细表tb_order_detail
id order_id product_id price cnt
1 301001 8002 150 1
2 301011
8003
200 1
3 301011
8001
80
1
4 301002
8001
85 1
5 301002
8003
180 1
6 301003
8002
140 1
7 301003
8003
180 1
8 301013
8002
140 2
9 301005
8003
180 1
(order_id-订单号, product_id-商品ID, price-商品单价, cnt-下单数量)


场景逻辑说明
  • 用户将购物车中多件商品一起下单时,订单总表会生成一个订单(但此时未付款, status-订单状态-订单状态0表示待付款),在订单明细表生成该订单中每个商品的信息;

  • 当用户支付完成时,在订单总表修改对应订单记录的status-订单状态-订单状态1表示已付款;

  • 若用户退货退款,在订单总表生成一条交易总金额为负值的记录(表示退款金额,订单号为退款单号,订单状态为2表示已退款)。


问题:请统计零食类商品中复购率top3高的商品。

复购率指用户在一段时间内对某商品的重复购买比例,复购率越大,则反映出消费者对品牌的忠诚度就越高,也叫回头率
此处我们定义:某商品复购率 = 近90天内购买它至少两次的人数 ÷ 购买它的总人数
近90天指包含最大日期(记为当天)在内的近90天。结果中复购率保留3位小数,并按复购率倒序、商品ID升序排序

输出示例
示例数据的输出结果如下:
product_id repurchase_rate
8001 1.000
8002 0.500
8003 0.333
解释:
商品8001、8002、8003都是零食类商品,8001只被用户102购买了两次,复购率1.000;
商品8002被101购买了两次,被105购买了1次,复购率0.500;
商品8003被102购买两次,被101和105各购买1次,复购率为0.333。
示例1

输入

DROP TABLE IF EXISTS tb_order_overall;
CREATE TABLE tb_order_overall (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    order_id INT NOT NULL COMMENT '订单号',
    uid INT NOT NULL COMMENT '用户ID',
    event_time datetime COMMENT '下单时间',
    total_amount DECIMAL NOT NULL COMMENT '订单总金额',
    total_cnt INT NOT NULL COMMENT '订单商品总件数',
    `status` TINYINT NOT NULL COMMENT '订单状态'
) CHARACTER SET utf8 COLLATE utf8_bin;

DROP TABLE IF EXISTS tb_product_info;
CREATE TABLE tb_product_info (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    product_id INT NOT NULL COMMENT '商品ID',
    shop_id INT NOT NULL COMMENT '店铺ID',
    tag VARCHAR(12) COMMENT '商品类别标签',
    in_price DECIMAL NOT NULL COMMENT '进货价格',
    quantity INT NOT NULL COMMENT '进货数量',
    release_time datetime COMMENT '上架时间'
) CHARACTER SET utf8 COLLATE utf8_bin;

DROP TABLE IF EXISTS tb_order_detail;
CREATE TABLE tb_order_detail (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '自增ID',
    order_id INT NOT NULL COMMENT '订单号',
    product_id INT NOT NULL COMMENT '商品ID',
    price DECIMAL NOT NULL COMMENT '商品单价',
    cnt INT NOT NULL COMMENT '下单数量'
) CHARACTER SET utf8 COLLATE utf8_bin;

INSERT INTO tb_product_info(product_id, shop_id, tag, in_price, quantity, release_time) VALUES
  (8001, 901, '零食', 60, 1000, '2020-01-01 10:00:00'),
  (8002, 901, '零食', 140, 500, '2020-01-01 10:00:00'),
  (8003, 901, '零食', 160, 500, '2020-01-01 10:00:00');

INSERT INTO tb_order_overall(order_id, uid, event_time, total_amount, total_cnt, `status`) VALUES
  (301001, 101, '2021-09-30 10:00:00', 140, 1, 1),
  (301002, 102, '2021-10-01 11:00:00', 235, 2, 1),
  (301011, 102, '2021-10-31 11:00:00', 250, 2, 1),
  (301003, 101, '2021-11-02 10:00:00', 300, 2, 1),
  (301013, 105, '2021-11-02 10:00:00', 300, 2, 1),
  (301005, 104, '2021-11-03 10:00:00', 170, 1, 1);

INSERT INTO tb_order_detail(order_id, product_id, price, cnt) VALUES
  (301001, 8002, 150, 1),
  (301011, 8003, 200, 1),
  (301011, 8001, 80, 1),
  (301002, 8001, 85, 1),
  (301002, 8003, 180, 1),
  (301003, 8002, 140, 1),
  (301003, 8003, 180, 1),
  (301013, 8002, 140, 2),
  (301005, 8003, 180, 1);

输出

8001|1.000
8002|0.500
8003|0.333
测试了半天没通过用例,原来是题目表述没理解
(1)题目意思:考虑表格tb_order_overall中最大日期往前数90天,这个时间周期内的复购情况
(2)个人理解:考虑商品被购买的相邻的两次时间,如果小于90天,则算复购(好像比题目麻烦...)
题目解法:
select product_id,round(sum(if(repurchase_cnt>1,1,0))/count(uid),3) repurchase_rate from 
(select uid,b.product_id product_id,sum(if(timestampdiff(day,date_format(event_time,'%Y-%m-%d'),date_format((select max(event_time) from tb_order_overall ),'%Y-%m-%d'))<90,1,0)) repurchase_cnt
from tb_order_detail a left join tb_product_info b on a.product_id=b.product_id left join tb_order_overall c on a.order_id=c.order_id
where tag='零食' group by uid,b.product_id) d
group by product_id
order by repurchase_rate desc,product_id limit 3;
按个人理解的复购率解法(用窗口函数获取相邻两次购买日期和购买人员):
with c as
(select a.product_id product_id,uid uid1,date_format(event_time,'%Y-%m-%d') d1, lead(date_format(event_time,'%Y-%m-%d'),1) over (partition by a.product_id order by date_format(event_time,'%Y-%m-%d')) d2,
 lead(uid,1) over(partition by product_id order by date_format(event_time,'%Y-%m-%d')) uid2
from tb_order_detail a left join tb_product_info b on a.product_id=b.product_id left join tb_order_overall c on a.order_id=c.order_id
where tag='零食')

select product_id,ifnull(round(sum(if(uid1=uid2 and TIMESTAMPDIFF(day,d1,d2)<90,1,0)) /count(distinct uid1,uid2),3),0.000) repurchase_rate
from c  group by product_id
order by repurchase_rate desc,product_id asc limit 3;
个人理解在其中一个测试用例报错,是因为商品8002在2021-08-05的记录,由于与表tb_order_overall中最大日期2021-11-03相差90天,所以8002不应被算入复购;但是8002实际上在2021-08-05与2021-08-06被uid101的用户分别购买,因而算在个人理解的复购中


发表于 2021-12-29 15:54:26 回复(7)
#一、先把90天内零食类商品的所有相关记录筛选出来
with t as (select b.product_id product_id,uid
from tb_order_overall a left join tb_order_detail b on a.order_id = b.order_id
left join tb_product_info c on c.product_id = b.product_id
where tag = '零食' and event_time BETWEEN date_sub((select max(event_time) from tb_order_overall),INTERVAL 89 day)
and (select max(event_time) from tb_order_overall) )
#二、计算复购率并输出结果
select a.product_id,round(复购人数/总人数,3) repurchase_rate
from 
(select product_id,(case when count(uid)>=2 then count(distinct uid) else 0 end) 复购人数
from t 
group by product_id,uid
) a #表a计算各零食类商品复购人数
                  right join (
select product_id,count(distinct uid) 总人数
from t 
group by product_id) b on a.product_id = b.product_id #表b计算各零食类商品总人数
order by repurchase_rate desc,product_id 
limit 3

代码有点长 但是应该比较好理解

发表于 2021-12-07 13:39:49 回复(3)
本质就是求一件商品被同一个人购买的次数与所有人购买次数的比值
with t as(
select
	t2.product_id,t1.uid,
	count(*) cnt
from
tb_order_overall t1
left join tb_order_detail t2
on t1.order_id=t2.order_id
left join tb_product_info t3
on t2.product_id=t3.product_id
where date(event_time)>(
select date(date_sub(max(event_time),interval 90 day)) from tb_order_overall)
and t3.tag='零食'
group by 1,2)
select product_id,round(sum(if(cnt>=2,1,0))/count(*),3) repurchase_rate from t group by product_id
order by 2 desc,1 limit 3

发表于 2022-01-04 09:39:05 回复(0)
select product_id,round(sum(case when ranking>1 then 1 else 0 end)/count(DISTINCT uid),3) rate from 
(select product_id,uid,ROW_NUMBER() over(partition by product_id,uid order by event_time) ranking
from tb_order_detail left join tb_product_info using (product_id) left JOIN tb_order_overall using (order_id)
where tag='零食' and status=1 and datediff((select max(event_time) from tb_order_overall),event_time)<90)t
group by  product_id
order by rate desc,product_id asc
limit 3
思路是用窗口函数筛出购买了两次的人

发表于 2021-12-08 14:06:29 回复(7)
select product_id,round(sum(cnt)/count(cnt),3) repurchase_rate
from
(select t1.product_id,uid,if(count(event_time)>=2,1,0) cnt
from tb_product_info t1
join tb_order_detail t3
on t1.product_id=t3.product_id
join tb_order_overall t2
on t2.order_id=t3.order_id
where status=1 and tag='零食' 
and datediff(date((select max(event_time) from tb_order_overall)),date(event_time))<90
group by product_id,uid) t
group by product_id
ORDER BY repurchase_rate DESC, product_id
LIMIT 3;
不太清楚是否需要status=1这个条件,有人解答一下吗
发表于 2021-12-20 09:51:34 回复(7)

【类型】:时间函数经典题

【场景】:留存率、复购率、

【分类】:时间函数

分析思路

难点:

1.时间函数的应用
2.复购率

(1)统计每个货物用户的购买记录;利用窗口函数根据货号、用户分组按购买时间排序

  • [使用] row_number();timestampdiff()

(2)统计零食类商品中复购率top3高的商品

求解代码

在时间的处理上,可能会遇到的问题,关于timestampdiff

错误代码1

#统计零食类商品中复购率top3高的商品
select
    product_id,
    round(count(distinct if(ranking >= 2,uid,null))/count(distinct uid),3) rate
from(
    #统计每个货物用户的购买记录;利用窗口函数根据货号、用户分组按购买时间排序
    select
        product_id,
        uid,
        row_number() over(partition by product_id,uid order by event_time) ranking
    from tb_order_detail
    left join tb_product_info using(product_id)
    left join tb_order_overall using (order_id)
    where tag='零食'
    and status=1
    and 90 > timestampdiff(day,event_time,(
        select
            max(date(event_time))
        from tb_order_overall))
) main
group by product_id
order by rate desc,product_id
limit 3

错误代码2

#统计零食类商品中复购率top3高的商品
select
    product_id,
    round(count(distinct if(ranking >= 2,uid,null))/count(distinct uid),3) rate
from(
    #统计每个货物用户的购买记录;利用窗口函数根据货号、用户分组按购买时间排序
    select
        product_id,
        uid,
        row_number() over(partition by product_id,uid order by event_time) ranking
    from tb_order_detail
    left join tb_product_info using(product_id)
    left JOIN tb_order_overall using (order_id)
    where tag='零食'
    and status=1
    and 90 > timestampdiff(date(
        (select
            max(event_time)
        from tb_order_overall)),date(event_time))
) main
group by product_id
order by rate desc,product_id
limit 3

不通过案例输出

1    8002|0.500        
2    8004|0.500    1    8004|0.500
3    8003|0.333    2    8003|0.333  
                   3    8002|0.000

在时间的处理上,为什么使用timestampdiff()会导致提交不通过,但使用datediff()和date_sub就可以,因为用错了timestampdiff()

正确代码

方法一

with子句

#统计零食类商品中复购率top3高的商品
with
    main as(
        #统计近90天内购买商品至少两次的人数
        select
            uid,
            product_id,
            count(distinct uid) as payusr_num
        from tb_product_info
        join tb_order_detail using(product_id)
        join tb_order_overall using(order_id)
        where tag = '零食'
        and status=1
        and date(event_time) > (
            select
                date(date_sub(max(event_time),interval 90 day))
            from tb_order_overall)
        group by product_id,uid having count(*) >= 2
    )
    ,attr as(
        #统计近90天内购买商品的总人数
        select
            product_id,
            if(count(distinct uid) = 0,0,count(distinct uid)) as usr_num
        from tb_product_info
        join tb_order_detail using(product_id)
        join tb_order_overall using(order_id)
        where tag = '零食'
        and status=1
        and date(event_time) > (
            select
                date(date_sub(max(event_time),interval 90 day))
            from tb_order_overall)
        group by product_id
    )
select
    product_id,
    round(if(payusr_num is null,0,payusr_num/usr_num),3) as repurchase_rate
from main
right join attr using(product_id)
order by repurchase_rate desc
limit 3

使用datediff()

#统计零食类商品中复购率top3高的商品
select
    product_id,
    round(count(distinct if(ranking >= 2,uid,null))/count(distinct uid),3) rate
from(
    #统计每个货物用户的购买记录;利用窗口函数根据货号、用户分组按购买时间排序
    #在时间的处理上,这道题不知道为什么不能使用timestampdiff(),会导致提交不通过
    #使用datediff()和date_sub就可以
    select
        product_id,
        uid,
        row_number() over(partition by product_id,uid order by event_time) ranking
    from tb_order_detail
    left join tb_product_info using(product_id)
    left JOIN tb_order_overall using (order_id)
    where tag='零食'
    and status=1
    and datediff(date(
        (select
            max(event_time)
        from tb_order_overall)),date(event_time)) < 90
) main
group by product_id
order by rate desc,product_id
limit 3

方法二

多表连接

#统计零食类商品中复购率top3高的商品
select
    product_id,
    round(count(distinct if(ranking >= 2,uid,null))/count(distinct uid),3) rate
from(
    #统计每个货物用户的购买记录;利用窗口函数根据货号、用户分组按购买时间排序
    #在时间的处理上,这道题不知道为什么不能使用timestampdiff(),会导致提交不通过
    #使用datediff()和date_sub就可以
    select
        product_id,
        uid,
        row_number() over(partition by product_id,uid order by event_time) ranking
    from tb_order_detail
    left join tb_product_info using(product_id)
    left JOIN tb_order_overall using (order_id)
    where tag='零食'
    and status=1
    and date(event_time) > date(
        (select
            date_sub(max(event_time),interval 90 day)
        from tb_order_overall)
        )
) main
group by product_id
order by rate desc,product_id
limit 3

输出结果

运行main表

1    8001|102|1    
2    8001|102|2    
3    8002|101|1    
4    8002|101|2        
5    8002|105|1        
6    8003|101|1        
7    8003|102|1        
8    8003|102|2        
9    8003|104|1
发表于 2022-11-06 23:38:29 回复(0)
看不懂你打我
# 问题:请统计零食类商品中复购率top3高的商品。
# 注:复购率指用户在一段时间内对某商品的重复购买比例,复购率越大,则反映出消费者对品牌的忠诚度就越高,也叫回头率
# 此处我们定义:某商品复购率 = 【近90天内】购买它至少两次的人数 ÷ 【近90天内】购买它的总人数
# 近90天指包含最大日期(记为当天)在内的近90天。结果中复购率保留3位小数,并按复购率倒序、商品ID升序排序

with total_info as(  # 建立大宽表
    select tod.*,too.uid,too.event_time,too.total_amount,too.total_cnt,too.status,
    tpi.shop_id,tpi.tag,tpi.in_price,tpi.quantity,tpi.release_time,
    max(event_time) over() as cur_time
    from tb_order_detail tod
    join tb_product_info tpi
    on tod.product_id=tpi.product_id
    join tb_order_overall too
    on too.order_id=tod.order_id
    where tpi.tag="零食"
)
,
repurchase  as(
    select product_id,uid,
    count(*) as purcharse_cnt
    from total_info
    where TIMESTAMPDIFF(day,event_time,cur_time)<90
    group by product_id,uid
)
,
t1 as( # repurcharse_flag为1表示此条记录被认为是有效复购,否则不是
    select product_id,purcharse_cnt,
    (case when purcharse_cnt>=2 then 1 else 0  end) as repurcharse_flag
    from repurchase
)

select product_id,
ROUND(sum(repurcharse_flag)/count(*),3) as repurchase_rate
from t1
group by product_id
order by repurchase_rate desc,product_id asc
limit 3


发表于 2023-03-22 11:01:35 回复(0)
select  product_id,round(sum(case when num >=2 then 1 else 0 end)/count(*),3) as repurchase_rate from (
select product_id,uid,count(*) as num
from tb_order_overall join tb_order_detail using(order_id)
join tb_product_info using(product_id)
where datediff((select max(date(event_time)) from tb_order_overall),date(event_time)) <90
and tag = '零食'
group by product_id,uid)t
group by product_id
order by repurchase_rate desc,product_id 
limit 3

嵌套from子查询

先算出每个产品,每个人购买过多少次,然后再计算复购率

发表于 2022-08-26 15:14:16 回复(1)
select product_id,
round(avg(case when cnt>=2 then 1 when cnt=1 then 0 end),3) repurchase_rate
from (
    select product_id,uid,count(*) cnt
    from (
        select c.product_id,b.uid,date(b.event_time) event_time,
        max(date(b.event_time)) over () max_time
        from tb_product_info a
        right join tb_order_detail c
        on a.product_id = c.product_id
        left join tb_order_overall b
        on c.order_id = b.order_id
        where a.tag = '零食' and b.status=1
        ) a
    where datediff(max_time,event_time) < 90
    group by product_id,uid
    ) t
group by product_id
order by repurchase_rate desc,product_id
limit 3;

发表于 2022-03-25 20:56:23 回复(0)
select product_id,round(sum(if(t_cnt=2,1,0))/count(distinct uid),3) repurchase_rate
from(
    select product_id,uid,row_number()over(partition by product_id,uid order by event_time) t_cnt
    from tb_order_detail
    left join tb_order_overall using(order_id)
    left join tb_product_info using(product_id)
    where tag='零食'
    and datediff((select max(event_time) 
                  from tb_order_overall)
                 ,event_time)<90
    and status<>2
) t
where t_cnt<3
group by product_id
order by repurchase_rate desc,product_id
limit 3;

发表于 2022-01-13 14:50:42 回复(0)
select b.product_id,
round(count(distinct c.uid)/(count(distinct b.uid)),3) repurchase_rate
from
(select distinct od1.product_id,o1.uid from tb_order_overall o1
inner join tb_order_detail od1 on od1.order_id = o1.order_id
inner join tb_product_info p1 on p1.product_id=od1.product_id
where p1.tag='零食'
and o1.status=1) as b
left join
(select product_id,uid from 
(select od.product_id,o.uid,count(o.uid) cnt from tb_order_overall o
inner join tb_order_detail od on od.order_id = o.order_id
inner join tb_product_info p on p.product_id=od.product_id
where p.tag='零食'
and timestampdiff(day,date(o.event_time),(select max(date(event_time)) from tb_order_overall))<=89
and o.status=1
group by od.product_id,o.uid) as a 
where a.cnt >= 2) as c on c.product_id=b.product_id
group by b.product_id
order by repurchase_rate desc,b.product_id limit 3
很麻烦了,反面教材
发表于 2021-12-07 08:15:01 回复(0)
with c as 
(select
t3.product_id as pid,
t2.uid as uid,
date_format(event_time,'%Y-%m-%d') as dt,
# 得到每个商品每个用户最近下一次购买的日期
lead(date_format(event_time,'%Y-%m-%d'),1) over (partition by t3.product_id,t2.uid order by date_format(event_time,'%Y-%m-%d')) as dt2,
((select max(date_format(event_time,'%Y-%m-%d')) from tb_order_overall)) as today
from tb_order_detail t3 
left join tb_order_overall t2 on t2.order_id = t3.order_id
left join tb_product_info t1 on t1.product_id = t3.product_id
where t1.tag = '零食' 
)

select
pid,
round(count(distinct if ((datediff(today,dt)<=89) and dt2 is not null,uid,null))/count(distinct uid),3) as rate
from c
group by pid
order by rate desc,pid
limit 3

发表于 2023-11-07 11:22:13 回复(0)
select distinct 
    od.product_id,
    round(avg(if(count(uid) > 1,1,0)) over(partition by od.product_id),3) repurchase_rate
from tb_product_info pi
join tb_order_detail od
on pi.product_id = od.product_id
join tb_order_overall oo
on od.order_id = oo.order_id
where tag = '零食'
and date(event_time) > date_sub((select date(max(event_time)) from tb_order_overall),interval 90 day)
group by od.product_id,oo.uid
order by repurchase_rate desc,od.product_id
limit 3;

发表于 2023-09-14 20:35:47 回复(0)
select product_id,
round(count(distinct if(purchase_cnt_90>=2,uid,null))/count(distinct uid),3)
as repurchase_rate #第二步:计算复购率
from
(
select product_id,uid,
count(if(event_time>=date_sub((select max(event_time) from tb_order_overall),interval 89 day),od.order_id,null)) as purchase_cnt_90
from tb_order_detail as od
inner join
(select order_id,uid,date(event_time) as event_time from tb_order_overall) as oo 
on od.order_id=oo.order_id
where 
od.product_id in(select product_id from tb_product_info where tag='零食')
group by product_id,uid 
) as od1 #第一步:计算零食类产品、用户及对应90天内购买产品的数量
group by product_id
order by repurchase_rate desc,product_id asc
limit 3;#第三步:选取top3

发表于 2023-02-22 20:32:45 回复(0)
with t1 as(
select order_id,uid,float_num,
    case
        when date(event_time) >= min_date then 1
        else 0
    end flag_date
from
(select order_id,uid,event_time,date_sub(date(max(event_time) over()),interval 89 day) min_date,
        case
            when status = 0 then 0
            when status = 1 then 1
            else -1
        end float_num
from tb_order_overall) oo
)
select product_id, round(sum(if(order_num>=2,1/order_num,0))/max(dr),3) repurchase_rate
from 
(
select od.product_id,uid,float_num,flag_date,sum(if(flag_date=1,float_num,0)) over(partition by product_id,uid) order_num,dense_rank() over(partition by product_id order by uid) dr
from t1
join tb_order_detail od
on t1.order_id = od.order_id
join (select product_id from tb_product_info where tag = '零食') pi
on od.product_id = pi.product_id
) t2
group by product_id
order by repurchase_rate desc
limit 3
思路
1.先对一个人下的订单状态打上标记(浮动购买次数)float_num,方便统计结果
2.使用窗口函数将最大日期之前的89天找到,并标记为min_date
3.对event_time使用case when打标记是否为有效复购日期
4.多表关联,关联商品信息表时过滤出tag为零食的商品
5.通过sum()窗口函数按照订单和用户分区后 累加有效复购日期中的浮动购买次数,
 通过dense_rank()窗口函数按照商品分区后再按照用户id进行排序,排序后可以通过max(排序结果)得出每个商品的购买人数
6.通过累加1/浮动购买次数大于两次的结果得到有效复购期内复购两次或以上的总人数(使用1/结果的原因:同一个人同一个商品如果购买了多次,会统计多次结果)
7.使用上面的人数除以排序的最大结果即购买某个商品的总人数即可得出复购率,对复购率排序后取前三位
发表于 2022-09-24 07:55:45 回复(0)
#  我麻了,线上测试通过,一提交就错,理了一下午,还是过不去,小伙伴们帮忙看看呗
# 第一步
WITH t0 AS
(
SELECT
    t1.product_id,t2.uid
    ,COUNT(*) AS uid_pay_cnt -- 用户付款次数
    ,IF(COUNT(*)>=2,1,0) AS fguid-- 是否复购用户
FROM tb_order_detail t1-- 订单明细表
    LEFT JOIN tb_order_overall t2 ON t1.order_id = t2.order_id-- 订单总表
    LEFT JOIN tb_product_info t3 ON t1.product_id= t3.product_id-- 商品信息表
WHERE
    -- 近90天
    t2.event_time >= DATE_SUB((SELECT MAX(event_time) FROM tb_order_detail),INTERVAL 89 DAY)
    -- 筛选'零食'&剔除退款记录
    AND t3.tag='零食' AND t2.status != 2
GROUP BY t1.product_id,t2.uid -- “计算字段”发生的层次
)
# 第二步

SELECT
    product_id
    ,ROUND(SUM(fguid) / COUNT(uid),3) AS repurchase_rate
FROM t0
GROUP BY product_id
ORDER BY repurchase_rate DESC,product_id
LIMIT 3

发表于 2022-07-23 18:15:45 回复(3)
with base as
(select uid,product_id from tb_product_info
join tb_order_detail using(product_id)
join tb_order_overall using(order_id)
where status=1
and tag='零食'
and timestampdiff(day,event_time,(select max(event_time) from tb_order_overall)) between 0 and 89)

select t1.product_id,ifnull(round(cnt_u/cnt_p,3),0) repurchase_rate from 
(select product_id,count(distinct uid) cnt_p from base group by product_id) t1
left join
(select product_id,uid,count(distinct uid) cnt_u from base group by product_id,uid
having count(uid)>=2)t2
on t1.product_id=t2.product_id
order by repurchase_rate desc,product_id
limit 3

发表于 2022-03-28 17:27:18 回复(1)
with new_tab as 
(select * from 
    (select a.uid,a.order_id,b.product_id,a.event_time
    from tb_order_overall a,tb_order_detail b,tb_product_info c 
    where a.order_id=b.order_id and b.product_id=c.product_id
    and a.status=1 and c.tag='零食') t 
left join 
     (select max(event_time) as max_time from tb_order_overall) t2 on 1=1
     where datediff(max_time,event_time) between 0 and 89
)

select t2.product_id,round(if(re_cnt is null,0,re_cnt)/pro_cnt,3) as repurchase_rate
from
    (select product_id,count(distinct uid) as pro_cnt from new_tab group by product_id) t2
left join 
    (select product_id,count(distinct uid) as re_cnt
    from (select uid,product_id,count(product_id)over(partition by uid,product_id) as pur_cnt 
    from new_tab) t where pur_cnt>=2 group by product_id
    ) t1
on t1.product_id=t2.product_id
order by repurchase_rate desc,product_id limit 3

发表于 2022-03-22 12:53:58 回复(0)
俺这混乱的逻辑纯纯蒟蒻牛本牛
WITH A AS(
    SELECT tb_order_detail.*, uid, event_time
    FROM tb_order_detail 
    LEFT JOIN tb_order_overall USING(order_id)
    LEFT JOIN tb_product_info USING(product_id)
    WHERE date(event_time) > (
        SELECT date(date_sub(max(event_time),interval 90 day)) FROM tb_order_overall
    )
    AND tag = '零食'
), B AS(
SELECT product_id, uid, COUNT(*) AS cc
FROM A
GROUP BY product_id, uid
), C AS(
    SELECT product_id, COUNT(*) AS cf
    FROM B WHERE cc >= 2
    GROUP BY product_id
), D AS(
    SELECT product_id, COUNT(*) AS cp
    FROM B
    GROUP BY product_id
)
SELECT product_id, ROUND(IFNULL(cf/cp, 0), 3) AS rate
FROM D 
LEFT JOIN C USING(product_id)
ORDER BY rate DESC, product_id ASC
LIMIT 3


发表于 2024-04-22 13:09:50 回复(0)
with basic_info as (
    select  
    a.order_id, # 订单号
    # a.cnt, # 订单数量
    c.uid,
    a.product_id,
    row_number()over(partition by c.uid,a.product_id order by c.event_time) as rk
    from tb_order_detail a
    join tb_product_info b
    on a.product_id = b.product_id
    join tb_order_overall c
    on a.order_id =c.order_id
    where b.tag = '零食'
    and status = 1
    and datediff((select date(max(event_time)) from tb_order_overall),date(c.event_time))<90
)
select 
product_id,
round(sum(case when rk=2 then 1 else 0 end)/count(distinct uid),3) as repurchase_rate
from basic_info
group by product_id
order by repurchase_rate desc,product_id asc
limit 3

编辑于 2024-04-21 09:52:00 回复(0)

问题信息

难度:
212条回答 1569浏览

热门推荐

通过挑战的用户

查看代码
  • 二维码

    扫描二维码,关注牛客网

  • 二维码

    下载牛客APP,随时随地刷题